diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/lldb | |
parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) |
Diffstat (limited to 'contrib/llvm-project/lldb')
565 files changed, 18330 insertions, 10774 deletions
diff --git a/contrib/llvm-project/lldb/bindings/headers.swig b/contrib/llvm-project/lldb/bindings/headers.swig index 408db90b925f..c0dde905f986 100644 --- a/contrib/llvm-project/lldb/bindings/headers.swig +++ b/contrib/llvm-project/lldb/bindings/headers.swig @@ -8,6 +8,8 @@ %{ #include "lldb/lldb-public.h" #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" @@ -19,6 +21,7 @@ #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommunication.h" #include "lldb/API/SBCompileUnit.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBData.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDeclaration.h" @@ -36,6 +39,7 @@ #include "lldb/API/SBHostOS.h" #include "lldb/API/SBInstruction.h" #include "lldb/API/SBInstructionList.h" +#include "lldb/API/SBLanguages.h" #include "lldb/API/SBLanguageRuntime.h" #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBLineEntry.h" @@ -54,6 +58,7 @@ #include "lldb/API/SBScriptObject.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" #include "lldb/API/SBStructuredData.h" diff --git a/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeDocstrings.i new file mode 100644 index 000000000000..650195704d73 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeDocstrings.i @@ -0,0 +1,3 @@ +%feature("docstring", +"API clients can get address range information." +) lldb::SBAddressRange; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeExtensions.i b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeExtensions.i new file mode 100644 index 000000000000..31bcfcb64590 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeExtensions.i @@ -0,0 +1,11 @@ +%extend lldb::SBAddressRange { +#ifdef SWIGPYTHON + %pythoncode%{ + def __repr__(self): + import lldb + stream = lldb.SBStream() + self.GetDescription(stream, lldb.target if lldb.target else lldb.SBTarget()) + return stream.GetData() + %} +#endif +} diff --git a/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListDocstrings.i new file mode 100644 index 000000000000..e4b96b9ca593 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListDocstrings.i @@ -0,0 +1,3 @@ +%feature("docstring", +"Represents a list of :py:class:`SBAddressRange`." +) lldb::SBAddressRangeList; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListExtensions.i b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListExtensions.i new file mode 100644 index 000000000000..e281a84d73d2 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBAddressRangeListExtensions.i @@ -0,0 +1,29 @@ +%extend lldb::SBAddressRangeList { +#ifdef SWIGPYTHON + %pythoncode%{ + def __len__(self): + '''Return the number of address ranges in a lldb.SBAddressRangeList object.''' + return self.GetSize() + + def __iter__(self): + '''Iterate over all the address ranges in a lldb.SBAddressRangeList object.''' + return lldb_iter(self, 'GetSize', 'GetAddressRangeAtIndex') + + def __getitem__(self, idx): + '''Get the address range at a given index in an lldb.SBAddressRangeList object.''' + if not isinstance(idx, int): + raise TypeError("unsupported index type: %s" % type(idx)) + count = len(self) + if not (-count <= idx < count): + raise IndexError("list index out of range") + idx %= count + return self.GetAddressRangeAtIndex(idx) + + def __repr__(self): + import lldb + stream = lldb.SBStream() + self.GetDescription(stream, lldb.target if lldb.target else lldb.SBTarget()) + return stream.GetData() + %} +#endif +} diff --git a/contrib/llvm-project/lldb/bindings/interface/SBBreakpointDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBBreakpointDocstrings.i index 74c139d5d9fb..dca2819a9927 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBBreakpointDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBBreakpointDocstrings.i @@ -39,7 +39,7 @@ TestBreakpointIgnoreCount.py),:: #lldbutil.print_stacktraces(process) from lldbutil import get_stopped_thread thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint) - self.assertTrue(thread != None, 'There should be a thread stopped due to breakpoint') + self.assertTrue(thread is not None, 'There should be a thread stopped due to breakpoint') frame0 = thread.GetFrameAtIndex(0) frame1 = thread.GetFrameAtIndex(1) frame2 = thread.GetFrameAtIndex(2) diff --git a/contrib/llvm-project/lldb/bindings/interface/SBCommandInterpreterRunOptionsDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBCommandInterpreterRunOptionsDocstrings.i index b37da0535d18..a4398d95ed0d 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBCommandInterpreterRunOptionsDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBCommandInterpreterRunOptionsDocstrings.i @@ -10,5 +10,8 @@ A default SBCommandInterpreterRunOptions object has: * PrintResults: true * PrintErrors: true * AddToHistory: true +* AllowRepeats false +Interactive debug sessions always allow repeats, the AllowRepeats +run option only affects non-interactive sessions. ") lldb::SBCommandInterpreterRunOptions; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBDataExtensions.i b/contrib/llvm-project/lldb/bindings/interface/SBDataExtensions.i index d980e79221c6..ddea77a088df 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBDataExtensions.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBDataExtensions.i @@ -40,19 +40,19 @@ STRING_EXTENSION_OUTSIDE(SBData) lldbtarget = lldbdict['target'] else: lldbtarget = None - if target == None and lldbtarget != None and lldbtarget.IsValid(): + if target is None and lldbtarget is not None and lldbtarget.IsValid(): target = lldbtarget - if ptr_size == None: + if ptr_size is None: if target and target.IsValid(): ptr_size = target.addr_size else: ptr_size = 8 - if endian == None: + if endian is None: if target and target.IsValid(): endian = target.byte_order else: endian = lldbdict['eByteOrderLittle'] - if size == None: + if size is None: if value > 2147483647: size = 8 elif value < -2147483648: diff --git a/contrib/llvm-project/lldb/bindings/interface/SBFrameExtensions.i b/contrib/llvm-project/lldb/bindings/interface/SBFrameExtensions.i index 43b22ed7a6b3..e0472280666a 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBFrameExtensions.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBFrameExtensions.i @@ -44,6 +44,16 @@ STRING_EXTENSION_OUTSIDE(SBFrame) def __init__(self, regs): self.regs = regs + def __iter__(self): + return self.get_registers() + + def get_registers(self): + for i in range(0,len(self.regs)): + rs = self.regs[i] + for j in range (0,rs.num_children): + reg = rs.GetChildAtIndex(j) + yield reg + def __getitem__(self, key): if type(key) is str: for i in range(0,len(self.regs)): @@ -52,7 +62,7 @@ STRING_EXTENSION_OUTSIDE(SBFrame) reg = rs.GetChildAtIndex(j) if reg.name == key: return reg else: - return lldb.SBValue() + return SBValue() return registers_access(self.registers) diff --git a/contrib/llvm-project/lldb/bindings/interface/SBMemoryRegionInfoDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBMemoryRegionInfoDocstrings.i index bd80740f3fdd..d7c68baf100e 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBMemoryRegionInfoDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBMemoryRegionInfoDocstrings.i @@ -2,8 +2,7 @@ "API clients can get information about memory regions in processes." ) lldb::SBMemoryRegionInfo; -%feature("autodoc", " - GetRegionEnd(SBMemoryRegionInfo self) -> lldb::addr_t +%feature("docstring", " Returns whether this memory region has a list of modified (dirty) pages available or not. When calling GetNumDirtyPages(), you will have 0 returned for both \"dirty page list is not known\" and @@ -11,8 +10,7 @@ memory region). You must use this method to disambiguate." ) lldb::SBMemoryRegionInfo::HasDirtyMemoryPageList; -%feature("autodoc", " - GetNumDirtyPages(SBMemoryRegionInfo self) -> uint32_t +%feature("docstring", " Return the number of dirty (modified) memory pages in this memory region, if available. You must use the SBMemoryRegionInfo::HasDirtyMemoryPageList() method to @@ -20,16 +18,14 @@ on the target system can provide this information." ) lldb::SBMemoryRegionInfo::GetNumDirtyPages; -%feature("autodoc", " - GetDirtyPageAddressAtIndex(SBMemoryRegionInfo self, uint32_t idx) -> lldb::addr_t +%feature("docstring", " Return the address of a modified, or dirty, page of memory. If the provided index is out of range, or this memory region does not have dirty page information, LLDB_INVALID_ADDRESS is returned." ) lldb::SBMemoryRegionInfo::GetDirtyPageAddressAtIndex; -%feature("autodoc", " - GetPageSize(SBMemoryRegionInfo self) -> int +%feature("docstring", " Return the size of pages in this memory region. 0 will be returned if this information was unavailable." ) lldb::SBMemoryRegionInfo::GetPageSize(); diff --git a/contrib/llvm-project/lldb/bindings/interface/SBProcessDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBProcessDocstrings.i index 3ee17e0c7f2f..1b98a79e4f6d 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBProcessDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBProcessDocstrings.i @@ -20,18 +20,18 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: " ) lldb::SBProcess; -%feature("autodoc", " +%feature("docstring", " Writes data into the current process's stdin. API client specifies a Python string as the only argument." ) lldb::SBProcess::PutSTDIN; -%feature("autodoc", " +%feature("docstring", " Reads data from the current process's stdout stream. API client specifies the size of the buffer to read data into. It returns the byte buffer in a Python string." ) lldb::SBProcess::GetSTDOUT; -%feature("autodoc", " +%feature("docstring", " Reads data from the current process's stderr stream. API client specifies the size of the buffer to read data into. It returns the byte buffer in a Python string." @@ -47,34 +47,34 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: "See SBTarget.Launch for argument description and usage." ) lldb::SBProcess::RemoteLaunch; -%feature("autodoc", " +%feature("docstring", " Returns the INDEX'th thread from the list of current threads. The index of a thread is only valid for the current stop. For a persistent thread identifier use either the thread ID or the IndexID. See help on SBThread for more details." ) lldb::SBProcess::GetThreadAtIndex; -%feature("autodoc", " +%feature("docstring", " Returns the thread with the given thread ID." ) lldb::SBProcess::GetThreadByID; -%feature("autodoc", " +%feature("docstring", " Returns the thread with the given thread IndexID." ) lldb::SBProcess::GetThreadByIndexID; -%feature("autodoc", " +%feature("docstring", " Returns the currently selected thread." ) lldb::SBProcess::GetSelectedThread; -%feature("autodoc", " +%feature("docstring", " Lazily create a thread on demand through the current OperatingSystem plug-in, if the current OperatingSystem plug-in supports it." ) lldb::SBProcess::CreateOSPluginThread; -%feature("autodoc", " +%feature("docstring", " Returns the process ID of the process." ) lldb::SBProcess::GetProcessID; -%feature("autodoc", " +%feature("docstring", " Returns an integer ID that is guaranteed to be unique across all process instances. This is not the process ID, just a unique integer for comparison and caching purposes." ) lldb::SBProcess::GetUniqueID; @@ -95,7 +95,7 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: will always increase, but may increase by more than one per stop." ) lldb::SBProcess::GetStopID; -%feature("autodoc", " +%feature("docstring", " Reads memory from the current process's address space and removes any traps that may have been inserted into the memory. It returns the byte buffer in a Python string. Example: :: @@ -105,7 +105,7 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: new_bytes = bytearray(content)" ) lldb::SBProcess::ReadMemory; -%feature("autodoc", " +%feature("docstring", " Writes memory to the current process's address space and maintains any traps that might be present due to software breakpoints. Example: :: @@ -116,8 +116,8 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: print('SBProcess.WriteMemory() failed!')" ) lldb::SBProcess::WriteMemory; -%feature("autodoc", " - Reads a NULL terminated C string from the current process's address space. +%feature("docstring", " + Reads a NUL terminated C string from the current process's address space. It returns a python string of the exact length, or truncates the string if the maximum character limit is reached. Example: :: @@ -131,7 +131,7 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: ) lldb::SBProcess::ReadCStringFromMemory; -%feature("autodoc", " +%feature("docstring", " Reads an unsigned integer from memory given a byte size and an address. Returns the unsigned integer that was read. Example: :: @@ -145,7 +145,7 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: ) lldb::SBProcess::ReadUnsignedFromMemory; -%feature("autodoc", " +%feature("docstring", " Reads a pointer from memory from an address and returns the value. Example: :: # Read a pointer from address 0x1000 @@ -158,16 +158,16 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: ) lldb::SBProcess::ReadPointerFromMemory; -%feature("autodoc", " +%feature("docstring", " Returns the implementation object of the process plugin if available. None otherwise." ) lldb::SBProcess::GetScriptedImplementation; -%feature("autodoc", " +%feature("docstring", " Returns the process' extended crash information." ) lldb::SBProcess::GetExtendedCrashInformation; -%feature("autodoc", " +%feature("docstring", " Load the library whose filename is given by image_spec looking in all the paths supplied in the paths argument. If successful, return a token that can be passed to UnloadImage and fill loaded_path with the path that was @@ -175,7 +175,7 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: lldb.LLDB_INVALID_IMAGE_TOKEN." ) lldb::SBProcess::LoadImageUsingPaths; -%feature("autodoc", " +%feature("docstring", " Return the number of different thread-origin extended backtraces this process can support as a uint32_t. When the process is stopped and you have an SBThread, lldb may be @@ -184,12 +184,12 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: queue)." ) lldb::SBProcess::GetNumExtendedBacktraceTypes; -%feature("autodoc", " +%feature("docstring", " Takes an index argument, returns the name of one of the thread-origin extended backtrace methods as a str." ) lldb::SBProcess::GetExtendedBacktraceTypeAtIndex; -%feature("autodoc", " +%feature("docstring", " Get information about the process. Valid process info will only be returned when the process is alive, use IsValid() to check if the info returned is valid. :: @@ -199,7 +199,48 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: process_info.GetProcessID()" ) lldb::SBProcess::GetProcessInfo; -%feature("autodoc", " +%feature("docstring", " + Get the current address mask in this Process of a given type. + There are lldb.eAddressMaskTypeCode and lldb.eAddressMaskTypeData address + masks, and on most Targets, the the Data address mask is more general + because there are no alignment restrictions, as there can be with Code + addresses. + lldb.eAddressMaskTypeAny may be used to get the most general mask. + The bits which are not used for addressing are set to 1 in the returned + mask. + In an unusual environment with different address masks for high and low + memory, this may also be specified. This is uncommon, default is + lldb.eAddressMaskRangeLow." +) lldb::SBProcess::GetAddressMask; + +%feature("docstring", " + Set the current address mask in this Process for a given type, + lldb.eAddressMaskTypeCode or lldb.eAddressMaskTypeData. Bits that are not + used for addressing should be set to 1 in the mask. + When setting all masks, lldb.eAddressMaskTypeAll may be specified. + In an unusual environment with different address masks for high and low + memory, this may also be specified. This is uncommon, default is + lldb.eAddressMaskRangeLow." +) lldb::SBProcess::SetAddressMask; + +%feature("docstring", " + Set the number of low bits relevant for addressing in this Process + for a given type, lldb.eAddressMaskTypeCode or lldb.eAddressMaskTypeData. + When setting all masks, lldb.eAddressMaskTypeAll may be specified. + In an unusual environment with different address masks for high and low + memory, the address range may also be specified. This is uncommon, + default is lldb.eAddressMaskRangeLow." +) lldb::SBProcess::SetAddressableBits; + +%feature("docstring", " + Given a virtual address, clear the bits that are not used for addressing + (and may be used for metadata, memory tagging, point authentication, etc). + By default the most general mask, lldb.eAddressMaskTypeAny is used to + process the address, but lldb.eAddressMaskTypeData and + lldb.eAddressMaskTypeCode may be specified if the type of address is known." +) lldb::SBProcess::FixAddress; + +%feature("docstring", " Allocates a block of memory within the process, with size and access permissions specified in the arguments. The permissions argument is an or-combination of zero or more of @@ -209,11 +250,11 @@ SBProcess supports thread iteration. For example (from test/lldbutil.py), :: lldb.LLDB_INVALID_ADDRESS if the allocation failed." ) lldb::SBProcess::AllocateMemory; -%feature("autodoc", "Get default process broadcaster class name (lldb.process)." +%feature("docstring", "Get default process broadcaster class name (lldb.process)." ) lldb::SBProcess::GetBroadcasterClass; -%feature("autodoc", " +%feature("docstring", " Deallocates the block of memory (previously allocated using AllocateMemory) given in the argument." ) lldb::SBProcess::DeallocateMemory; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBQueueDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBQueueDocstrings.i index fa472d5bed17..c3baf39a299d 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBQueueDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBQueueDocstrings.i @@ -2,14 +2,14 @@ "Represents a libdispatch queue in the process." ) lldb::SBQueue; -%feature("autodoc", " +%feature("docstring", " Returns an lldb::queue_id_t type unique identifier number for this queue that will not be used by any other queue during this process' execution. These ID numbers often start at 1 with the first system-created queues and increment from there." ) lldb::SBQueue::GetQueueID; -%feature("autodoc", " +%feature("docstring", " Returns an lldb::QueueKind enumerated value (e.g. eQueueKindUnknown, eQueueKindSerial, eQueueKindConcurrent) describing the type of this queue." diff --git a/contrib/llvm-project/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBSaveCoreOptionsDocstrings.i diff --git a/contrib/llvm-project/lldb/bindings/interface/SBStatisticsOptionsDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBStatisticsOptionsDocstrings.i new file mode 100644 index 000000000000..087f6ab87866 --- /dev/null +++ b/contrib/llvm-project/lldb/bindings/interface/SBStatisticsOptionsDocstrings.i @@ -0,0 +1,14 @@ +%feature("docstring", +"A container for options to use when dumping statistics." +) lldb::SBStatisticsOptions; + +%feature("docstring", "Sets whether the statistics should only dump a summary." +) lldb::SBStatisticsOptions::SetSummaryOnly; +%feature("docstring", "Gets whether the statistics only dump a summary." +) lldb::SBStatisticsOptions::GetSummaryOnly; +%feature("docstring", " + Sets whether the statistics will force loading all possible debug info." +) lldb::SBStatisticsOptions::SetReportAllAvailableDebugInfo; +%feature("docstring", " + Gets whether the statistics will force loading all possible debug info." +) lldb::SBStatisticsOptions::GetReportAllAvailableDebugInfo; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBTargetExtensions.i b/contrib/llvm-project/lldb/bindings/interface/SBTargetExtensions.i index c80dadfc0c5c..d756a351a810 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBTargetExtensions.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBTargetExtensions.i @@ -172,7 +172,7 @@ STRING_EXTENSION_LEVEL_OUTSIDE(SBTarget, lldb::eDescriptionLevelBrief) '''An accessor function that returns a list() that contains all watchpoints in a lldb.SBtarget object.''' watchpoints = [] for idx in range(self.GetNumWatchpoints()): - bkpts.append(self.GetWatchpointAtIndex(idx)) + watchpoints.append(self.GetWatchpointAtIndex(idx)) return watchpoints modules = property(get_modules_array, None, doc='''A read only property that returns a list() of lldb.SBModule objects contained in this target. This list is a list all modules that the target currently is tracking (the main executable and all dependent shared libraries).''') diff --git a/contrib/llvm-project/lldb/bindings/interface/SBThreadDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBThreadDocstrings.i index f307212f0114..76822e49c638 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBThreadDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBThreadDocstrings.i @@ -55,24 +55,24 @@ See also :py:class:`SBFrame` ." eStopReasonPlanComplete 0" ) lldb::SBThread::GetStopReasonDataAtIndex; -%feature("autodoc", " +%feature("docstring", " Collects a thread's stop reason extended information dictionary and prints it into the SBStream in a JSON format. The format of this JSON dictionary depends on the stop reason and is currently used only for instrumentation plugins." ) lldb::SBThread::GetStopReasonExtendedInfoAsJSON; -%feature("autodoc", " +%feature("docstring", " Returns a collection of historical stack traces that are significant to the current stop reason. Used by ThreadSanitizer, where we provide various stack traces that were involved in a data race or other type of detected issue." ) lldb::SBThread::GetStopReasonExtendedBacktraces; -%feature("autodoc", " +%feature("docstring", " Pass only an (int)length and expect to get a Python string describing the stop reason." ) lldb::SBThread::GetStopDescription; -%feature("autodoc", " +%feature("docstring", " Returns a unique thread identifier (type lldb::tid_t, typically a 64-bit type) for the current SBThread that will remain constant throughout the thread's lifetime in this process and will not be reused by another thread during this @@ -81,7 +81,7 @@ See also :py:class:`SBFrame` ." to associate data from those tools with lldb. See related GetIndexID." ) lldb::SBThread::GetThreadID; -%feature("autodoc", " +%feature("docstring", " Return the index number for this SBThread. The index number is the same thing that a user gives as an argument to 'thread select' in the command line lldb. These numbers start at 1 (for the first thread lldb sees in a debug session) @@ -91,12 +91,12 @@ See also :py:class:`SBFrame` ." This method returns a uint32_t index number, takes no arguments." ) lldb::SBThread::GetIndexID; -%feature("autodoc", " +%feature("docstring", " Return the queue name associated with this thread, if any, as a str. For example, with a libdispatch (aka Grand Central Dispatch) queue." ) lldb::SBThread::GetQueueName; -%feature("autodoc", " +%feature("docstring", " Return the dispatch_queue_id for this thread, if any, as a lldb::queue_id_t. For example, with a libdispatch (aka Grand Central Dispatch) queue." ) lldb::SBThread::GetQueueID; @@ -109,7 +109,7 @@ See also :py:class:`SBFrame` ." anything was printed into the stream (true) or not (false)." ) lldb::SBThread::GetInfoItemByPathAsString; -%feature("autodoc", " +%feature("docstring", " Return the SBQueue for this thread. If this thread is not currently associated with a libdispatch queue, the SBQueue object's IsValid() method will return false. If this SBThread is actually a HistoryThread, we may be able to provide QueueID @@ -141,14 +141,14 @@ See also :py:class:`SBFrame` ." "Do an instruction level single step in the currently selected thread." ) lldb::SBThread::StepInstruction; -%feature("autodoc", " +%feature("docstring", " Force a return from the frame passed in (and any frames younger than it) without executing any more code in those frames. If return_value contains a valid SBValue, that will be set as the return value from frame. Note, at present only scalar return values are supported." ) lldb::SBThread::ReturnFromFrame; -%feature("autodoc", " +%feature("docstring", " Unwind the stack frames from the innermost expression evaluation. This API is equivalent to 'thread return -x'." ) lldb::SBThread::UnwindInnermostExpression; @@ -181,7 +181,7 @@ See also :py:class:`SBFrame` ." or thread-stop-format (stop_format = true)." ) lldb::SBThread::GetDescription; -%feature("autodoc"," +%feature("docstring"," Given an argument of str to specify the type of thread-origin extended backtrace to retrieve, query whether the origin of this thread is available. An SBThread is retured; SBThread.IsValid will return true @@ -192,8 +192,7 @@ See also :py:class:`SBFrame` ." the returned thread's own thread origin in turn." ) lldb::SBThread::GetExtendedBacktraceThread; -%feature("autodoc"," - Takes no arguments, returns a uint32_t. +%feature("docstring"," If this SBThread is an ExtendedBacktrace thread, get the IndexID of the original thread that this ExtendedBacktrace thread represents, if available. The thread that was running this backtrace in the past may @@ -202,29 +201,28 @@ See also :py:class:`SBFrame` ." In that case, this ExtendedBacktrace thread's IndexID will be returned." ) lldb::SBThread::GetExtendedBacktraceOriginatingIndexID; -%feature("autodoc"," +%feature("docstring"," Returns an SBValue object represeting the current exception for the thread, if there is any. Currently, this works for Obj-C code and returns an SBValue representing the NSException object at the throw site or that's currently being processes." ) lldb::SBThread::GetCurrentException; -%feature("autodoc"," +%feature("docstring"," Returns a historical (fake) SBThread representing the stack trace of an exception, if there is one for the thread. Currently, this works for Obj-C code, and can retrieve the throw-site backtrace of an NSException object even when the program is no longer at the throw site." ) lldb::SBThread::GetCurrentExceptionBacktrace; -%feature("autodoc"," - Takes no arguments, returns a bool. +%feature("docstring"," lldb may be able to detect that function calls should not be executed on a given thread at a particular point in time. It is recommended that this is checked before performing an inferior function call on a given thread." ) lldb::SBThread::SafeToCallFunctions; -%feature("autodoc"," - Retruns a SBValue object representing the siginfo for the current signal. +%feature("docstring"," + Returns a SBValue object representing the siginfo for the current signal. " ) lldb::SBThread::GetSiginfo; diff --git a/contrib/llvm-project/lldb/bindings/interface/SBValueDocstrings.i b/contrib/llvm-project/lldb/bindings/interface/SBValueDocstrings.i index 6bab923e8b35..59fa807f5ec9 100644 --- a/contrib/llvm-project/lldb/bindings/interface/SBValueDocstrings.i +++ b/contrib/llvm-project/lldb/bindings/interface/SBValueDocstrings.i @@ -135,6 +135,26 @@ linked list." %feature("docstring", "Expands nested expressions like .a->b[0].c[1]->d." ) lldb::SBValue::GetValueForExpressionPath; +%feature("docstring", " + Return the value as an address. On failure, LLDB_INVALID_ADDRESS + will be returned. On architectures like AArch64, where the + top (unaddressable) bits can be used for authentication, + memory tagging, or top byte ignore, this method will return + the value with those top bits cleared. + + GetValueAsUnsigned returns the actual value, with the + authentication/Top Byte Ignore/Memory Tagging Extension bits. + + Calling this on a random value which is not a pointer is + incorrect. Call GetType().IsPointerType() if in doubt. + + An SB API program may want to show both the literal byte value + and the address it refers to in memory. These two SBValue + methods allow SB API writers to behave appropriately for their + interface." +) lldb::SBValue::GetValueAsAddress; + + %feature("doctstring", " Returns the number for children. diff --git a/contrib/llvm-project/lldb/bindings/interfaces.swig b/contrib/llvm-project/lldb/bindings/interfaces.swig index 9ca479218f62..8a6fed95f0b7 100644 --- a/contrib/llvm-project/lldb/bindings/interfaces.swig +++ b/contrib/llvm-project/lldb/bindings/interfaces.swig @@ -12,6 +12,8 @@ /* Docstrings for SB classes and methods */ %include "./interface/SBAddressDocstrings.i" +%include "./interface/SBAddressRangeDocstrings.i" +%include "./interface/SBAddressRangeListDocstrings.i" %include "./interface/SBAttachInfoDocstrings.i" %include "./interface/SBBlockDocstrings.i" %include "./interface/SBBreakpointDocstrings.i" @@ -23,6 +25,7 @@ %include "./interface/SBCommandReturnObjectDocstrings.i" %include "./interface/SBCommunicationDocstrings.i" %include "./interface/SBCompileUnitDocstrings.i" +%include "./interface/SBSaveCoreOptionsDocstrings.i" %include "./interface/SBDataDocstrings.i" %include "./interface/SBDebuggerDocstrings.i" %include "./interface/SBDeclarationDocstrings.i" @@ -56,6 +59,7 @@ %include "./interface/SBReproducerDocstrings.i" %include "./interface/SBSectionDocstrings.i" %include "./interface/SBSourceManagerDocstrings.i" +%include "./interface/SBStatisticsOptionsDocstrings.i" %include "./interface/SBStreamDocstrings.i" %include "./interface/SBStringListDocstrings.i" %include "./interface/SBStructuredDataDocstrings.i" @@ -85,6 +89,8 @@ /* API headers */ %include "lldb/API/SBAddress.h" +%include "lldb/API/SBAddressRange.h" +%include "lldb/API/SBAddressRangeList.h" %include "lldb/API/SBAttachInfo.h" %include "lldb/API/SBBlock.h" %include "lldb/API/SBBreakpoint.h" @@ -96,6 +102,7 @@ %include "lldb/API/SBCommandReturnObject.h" %include "lldb/API/SBCommunication.h" %include "lldb/API/SBCompileUnit.h" +%include "lldb/API/SBSaveCoreOptions.h" %include "lldb/API/SBData.h" %include "lldb/API/SBDebugger.h" %include "lldb/API/SBDeclaration.h" @@ -113,6 +120,7 @@ %include "lldb/API/SBHostOS.h" %include "lldb/API/SBInstruction.h" %include "lldb/API/SBInstructionList.h" +%include "lldb/API/SBLanguages.h" %include "lldb/API/SBLanguageRuntime.h" %include "lldb/API/SBLaunchInfo.h" %include "lldb/API/SBLineEntry.h" @@ -131,6 +139,7 @@ %include "lldb/API/SBScriptObject.h" %include "lldb/API/SBSection.h" %include "lldb/API/SBSourceManager.h" +%include "lldb/API/SBStatisticsOptions.h" %include "lldb/API/SBStream.h" %include "lldb/API/SBStringList.h" %include "lldb/API/SBStructuredData.h" @@ -160,6 +169,8 @@ /* Extensions for SB classes */ %include "./interface/SBAddressExtensions.i" +%include "./interface/SBAddressRangeExtensions.i" +%include "./interface/SBAddressRangeListExtensions.i" %include "./interface/SBBlockExtensions.i" %include "./interface/SBBreakpointExtensions.i" %include "./interface/SBBreakpointListExtensions.i" diff --git a/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig b/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig index d5ea51487271..34f8c6f0ff8d 100644 --- a/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig +++ b/contrib/llvm-project/lldb/bindings/python/python-swigsafecast.swig @@ -37,10 +37,6 @@ PythonObject SWIGBridge::ToSWIGWrapper(const Status& status) { return ToSWIGHelper(new lldb::SBError(status), SWIGTYPE_p_lldb__SBError); } -PythonObject SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStream> stream_sb) { - return ToSWIGHelper(stream_sb.release(), SWIGTYPE_p_lldb__SBStream); -} - PythonObject SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb) { return ToSWIGHelper(data_sb.release(), SWIGTYPE_p_lldb__SBStructuredData); } @@ -115,9 +111,16 @@ SWIGBridge::ToSWIGWrapper(CommandReturnObject &cmd_retobj) { SWIGTYPE_p_lldb__SBCommandReturnObject); } -ScopedPythonObject<lldb::SBEvent> SWIGBridge::ToSWIGWrapper(Event *event) { - return ScopedPythonObject<lldb::SBEvent>(new lldb::SBEvent(event), - SWIGTYPE_p_lldb__SBEvent); +PythonObject SWIGBridge::ToSWIGWrapper(const Stream *s) { + return ToSWIGHelper(new lldb::SBStream(), SWIGTYPE_p_lldb__SBStream); +} + +PythonObject SWIGBridge::ToSWIGWrapper(std::shared_ptr<lldb::SBStream> stream_sb) { + return ToSWIGHelper(stream_sb.get(), SWIGTYPE_p_lldb__SBStream); +} + +PythonObject SWIGBridge::ToSWIGWrapper(Event *event) { + return ToSWIGHelper(new lldb::SBEvent(event), SWIGTYPE_p_lldb__SBEvent); } PythonObject SWIGBridge::ToSWIGWrapper( diff --git a/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig b/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig index 8d4b740e5f35..f8c33e15c03e 100644 --- a/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig +++ b/contrib/llvm-project/lldb/bindings/python/python-typemaps.swig @@ -257,7 +257,8 @@ AND call SWIG_fail at the same time, because it will result in a double free. } // For SBProcess::WriteMemory, SBTarget::GetInstructions and SBDebugger::DispatchInput. %typemap(in) (const void *buf, size_t size), - (const void *data, size_t data_len) { + (const void *data, size_t data_len), + (const void *buf, uint64_t size) { if (PythonString::Check($input)) { PythonString str(PyRefType::Borrowed, $input); $1 = (void *)str.GetString().data(); @@ -427,7 +428,6 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { free($1); } - // For Log::LogOutputCallback %typemap(in) (lldb::LogOutputCallback log_callback, void *baton) { if (!($input == Py_None || @@ -476,6 +476,23 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) { $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); } +%typemap(in) (lldb::CommandOverrideCallback callback, void *baton) { + if (!($input == Py_None || + PyCallable_Check(reinterpret_cast<PyObject *>($input)))) { + PyErr_SetString(PyExc_TypeError, "Need a callable object or None!"); + SWIG_fail; + } + + // Don't lose the callback reference. + Py_INCREF($input); + $1 = LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback; + $2 = $input; +} +%typemap(typecheck) (lldb::CommandOverrideCallback callback, void *baton) { + $1 = $input == Py_None; + $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input)); +} + %typemap(in) lldb::FileSP { PythonFile py_file(PyRefType::Borrowed, $input); if (!py_file) { diff --git a/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig b/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig index 17bc7b1f2198..8f050643fa68 100644 --- a/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig +++ b/contrib/llvm-project/lldb/bindings/python/python-wrapper.swig @@ -229,133 +229,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict); } -PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedThreadPlan( - const char *python_class_name, const char *session_dictionary_name, - const lldb_private::StructuredDataImpl &args_impl, - std::string &error_string, const lldb::ThreadPlanSP &thread_plan_sp) { - if (python_class_name == NULL || python_class_name[0] == '\0' || - !session_dictionary_name) - return PythonObject(); - - PyErr_Cleaner py_err_cleaner(true); - - auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( - session_dictionary_name); - auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( - python_class_name, dict); - - if (!pfunc.IsAllocated()) { - error_string.append("could not find script class: "); - error_string.append(python_class_name); - return PythonObject(); - } - - PythonObject tp_arg = SWIGBridge::ToSWIGWrapper(thread_plan_sp); - - llvm::Expected<PythonCallable::ArgInfo> arg_info = pfunc.GetArgInfo(); - if (!arg_info) { - llvm::handleAllErrors( - arg_info.takeError(), - [&](PythonException &E) { error_string.append(E.ReadBacktrace()); }, - [&](const llvm::ErrorInfoBase &E) { - error_string.append(E.message()); - }); - return PythonObject(); - } - - PythonObject result = {}; - auto args_sb = std::unique_ptr<lldb::SBStructuredData>(new lldb::SBStructuredData(args_impl)); - if (arg_info.get().max_positional_args == 2) { - if (args_sb->IsValid()) { - error_string.assign( - "args passed, but __init__ does not take an args dictionary"); - return PythonObject(); - } - result = pfunc(tp_arg, dict); - } else if (arg_info.get().max_positional_args >= 3) { - result = pfunc(tp_arg, SWIGBridge::ToSWIGWrapper(std::move(args_sb)), dict); - } else { - error_string.assign("wrong number of arguments in __init__, should be 2 or " - "3 (not including self)"); - return PythonObject(); - } - - // FIXME: At this point we should check that the class we found supports all - // the methods that we need. - - return result; -} - -bool lldb_private::python::SWIGBridge::LLDBSWIGPythonCallThreadPlan( - void *implementor, const char *method_name, lldb_private::Event *event, - bool &got_error) { - got_error = false; - - PyErr_Cleaner py_err_cleaner(false); - PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); - auto pfunc = self.ResolveName<PythonCallable>(method_name); - - if (!pfunc.IsAllocated()) - return false; - - PythonObject result; - if (event != nullptr) { - ScopedPythonObject<SBEvent> event_arg = SWIGBridge::ToSWIGWrapper(event); - result = pfunc(event_arg.obj()); - } else - result = pfunc(); - - if (PyErr_Occurred()) { - got_error = true; - printf("Return value was neither false nor true for call to %s.\n", - method_name); - PyErr_Print(); - return false; - } - - if (result.get() == Py_True) - return true; - else if (result.get() == Py_False) - return false; - - // Somebody returned the wrong thing... - got_error = true; - printf("Wrong return value type for call to %s.\n", method_name); - return false; -} - -bool lldb_private::python::SWIGBridge::LLDBSWIGPythonCallThreadPlan( - void *implementor, const char *method_name, lldb_private::Stream *stream, - bool &got_error) { - got_error = false; - - PyErr_Cleaner py_err_cleaner(false); - PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); - auto pfunc = self.ResolveName<PythonCallable>(method_name); - - if (!pfunc.IsAllocated()) - return false; - - auto *sb_stream = new lldb::SBStream(); - PythonObject sb_stream_arg = - SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStream>(sb_stream)); - - PythonObject result; - result = pfunc(sb_stream_arg); - - if (PyErr_Occurred()) { - printf("Error occured for call to %s.\n", - method_name); - PyErr_Print(); - got_error = true; - return false; - } - if (stream) - stream->PutCString(sb_stream->GetData()); - return true; - -} - PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( const char *python_class_name, const char *session_dictionary_name, const StructuredDataImpl &args_impl, @@ -500,9 +373,8 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonStopHookCallHandleStop( if (!pfunc.IsAllocated()) return true; - auto *sb_stream = new lldb::SBStream(); - PythonObject sb_stream_arg = - SWIGBridge::ToSWIGWrapper(std::unique_ptr<lldb::SBStream>(sb_stream)); + std::shared_ptr<lldb::SBStream> sb_stream = std::make_shared<lldb::SBStream>(); + PythonObject sb_stream_arg = SWIGBridge::ToSWIGWrapper(sb_stream); PythonObject result = pfunc(SWIGBridge::ToSWIGWrapper(std::move(exc_ctx_sp)), sb_stream_arg); @@ -517,6 +389,7 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonStopHookCallHandleStop( // makes an internally help StreamString which I can't interpose, so I // have to copy it over here. stream->PutCString(sb_stream->GetData()); + sb_stream_arg.release(); if (result.get() == Py_False) return false; @@ -753,6 +626,30 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBError(PyObject * data return sb_ptr; } +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBEvent(PyObject * data) { + lldb::SBEvent *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBEvent, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBStream(PyObject * data) { + lldb::SBStream *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBStream, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBValue(PyObject * data) { lldb::SBValue *sb_ptr = NULL; @@ -831,6 +728,51 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallCommandObject( return true; } +std::optional<std::string> +lldb_private::python::SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor, + std::string &command) { + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("get_repeat_command"); + // If not implemented, repeat the exact command. + if (!pfunc.IsAllocated()) + return std::nullopt; + + PythonString command_str(command); + PythonObject result = pfunc(command_str); + + // A return of None is the equivalent of nullopt - means repeat + // the command as is: + if (result.IsNone()) + return std::nullopt; + + return result.Str().GetString().str(); +} + +#include "lldb/Interpreter/CommandReturnObject.h" + +bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject( + PyObject *implementor, lldb::DebuggerSP debugger, lldb_private::StructuredDataImpl &args_impl, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp) { + + PyErr_Cleaner py_err_cleaner(true); + + PythonObject self(PyRefType::Borrowed, implementor); + auto pfunc = self.ResolveName<PythonCallable>("__call__"); + + if (!pfunc.IsAllocated()) { + cmd_retobj.AppendError("Could not find '__call__' method in implementation class"); + return false; + } + + pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger)), SWIGBridge::ToSWIGWrapper(args_impl), + SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp), SWIGBridge::ToSWIGWrapper(cmd_retobj).obj()); + + return true; +} + PythonObject lldb_private::python::SWIGBridge::LLDBSWIGPythonCreateOSPlugin( const char *python_class_name, const char *session_dictionary_name, const lldb::ProcessSP &process_sp) { @@ -1076,6 +1018,28 @@ static void LLDBSwigPythonCallPythonSBDebuggerTerminateCallback(lldb::user_id_t } } +static bool LLDBSwigPythonCallPythonSBCommandInterpreterSetCommandOverrideCallback(void *baton, const char **argv) { + bool ret_val = false; + if (baton != Py_None) { + SWIG_PYTHON_THREAD_BEGIN_BLOCK; + // Create a PyList of items since we're going to pass it to the callback as a tuple + // of arguments. + PyObject *py_argv = PyList_New(0); + for (const char **arg = argv; arg && *arg; arg++) { + std::string arg_string = *arg; + PyObject *py_string = PyUnicode_FromStringAndSize(arg_string.c_str(), arg_string.size()); + PyList_Append(py_argv, py_string); + } + + PyObject *result = PyObject_CallObject( + reinterpret_cast<PyObject *>(baton), PyList_AsTuple(py_argv)); + ret_val = result ? PyObject_IsTrue(result) : false; + Py_XDECREF(result); + SWIG_PYTHON_THREAD_END_BLOCK; + } + return ret_val; +} + static SBError LLDBSwigPythonCallLocateModuleCallback( void *callback_baton, const SBModuleSpec &module_spec_sb, SBFileSpec &module_file_spec_sb, SBFileSpec &symbol_file_spec_sb) { diff --git a/contrib/llvm-project/lldb/docs/python_extensions.rst b/contrib/llvm-project/lldb/docs/python_extensions.rst new file mode 100644 index 000000000000..7e5f1ba6879d --- /dev/null +++ b/contrib/llvm-project/lldb/docs/python_extensions.rst @@ -0,0 +1,39 @@ +Python Extensions +================= + +LLDB provides scriptable extensions to augment the debugger's capabilities. +This gives users the ability to tailor their debugging experience to their own needs. + +This page describes some of these scripting extensions: + +Operating System Thread Plugins +------------------------------- + +.. automodapi:: lldb.plugins.operating_system + :no-heading: + :skip: ScriptedThread + :no-inheritance-diagram: + +Scripted Process Plugins +------------------------------- + +.. automodapi:: lldb.plugins.scripted_process + :no-heading: + :skip: ABCMeta + :no-inheritance-diagram: + +Scripted Platform Plugins +------------------------------- + +.. automodapi:: lldb.plugins.scripted_platform + :no-heading: + :skip: ABCMeta + :no-inheritance-diagram: + +Scripted Thread Plan Plugins +------------------------------- + +.. automodapi:: lldb.plugins.scripted_thread_plan + :no-heading: + :no-inheritance-diagram: + diff --git a/contrib/llvm-project/lldb/include/lldb/API/LLDB.h b/contrib/llvm-project/lldb/include/lldb/API/LLDB.h index f5f1b87a046c..40368e036e0e 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/LLDB.h +++ b/contrib/llvm-project/lldb/include/lldb/API/LLDB.h @@ -10,6 +10,8 @@ #define LLDB_API_LLDB_H #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" @@ -40,6 +42,7 @@ #include "lldb/API/SBInstruction.h" #include "lldb/API/SBInstructionList.h" #include "lldb/API/SBLanguageRuntime.h" +#include "lldb/API/SBLanguages.h" #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBLineEntry.h" #include "lldb/API/SBListener.h" @@ -54,8 +57,10 @@ #include "lldb/API/SBQueue.h" #include "lldb/API/SBQueueItem.h" #include "lldb/API/SBReproducer.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBSection.h" #include "lldb/API/SBSourceManager.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" #include "lldb/API/SBStructuredData.h" diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBAddress.h b/contrib/llvm-project/lldb/include/lldb/API/SBAddress.h index 5e5f355ccc39..430dad4862db 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBAddress.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBAddress.h @@ -86,6 +86,7 @@ public: lldb::SBLineEntry GetLineEntry(); protected: + friend class SBAddressRange; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointLocation; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBAddressRange.h b/contrib/llvm-project/lldb/include/lldb/API/SBAddressRange.h new file mode 100644 index 000000000000..5c4d6b8c5683 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/API/SBAddressRange.h @@ -0,0 +1,72 @@ +//===-- SBAddressRange.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_API_SBADDRESSRANGE_H +#define LLDB_API_SBADDRESSRANGE_H + +#include "lldb/API/SBDefines.h" + +namespace lldb_private { +class AddressRange; +} + +namespace lldb { + +class LLDB_API SBAddressRange { +public: + SBAddressRange(); + + SBAddressRange(const lldb::SBAddressRange &rhs); + + SBAddressRange(lldb::SBAddress addr, lldb::addr_t byte_size); + + ~SBAddressRange(); + + const lldb::SBAddressRange &operator=(const lldb::SBAddressRange &rhs); + + void Clear(); + + /// Check the address range refers to a valid base address and has a byte + /// size greater than zero. + /// + /// \return + /// True if the address range is valid, false otherwise. + bool IsValid() const; + + /// Get the base address of the range. + /// + /// \return + /// Base address object. + lldb::SBAddress GetBaseAddress() const; + + /// Get the byte size of this range. + /// + /// \return + /// The size in bytes of this address range. + lldb::addr_t GetByteSize() const; + + bool operator==(const SBAddressRange &rhs); + + bool operator!=(const SBAddressRange &rhs); + + bool GetDescription(lldb::SBStream &description, const SBTarget target); + +private: + friend class SBAddressRangeList; + friend class SBBlock; + friend class SBFunction; + friend class SBProcess; + + lldb_private::AddressRange &ref() const; + + AddressRangeUP m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_API_SBADDRESSRANGE_H diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBAddressRangeList.h b/contrib/llvm-project/lldb/include/lldb/API/SBAddressRangeList.h new file mode 100644 index 000000000000..5a4eeecf37dc --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/API/SBAddressRangeList.h @@ -0,0 +1,56 @@ +//===-- SBAddressRangeList.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_API_SBADDRESSRANGELIST_H +#define LLDB_API_SBADDRESSRANGELIST_H + +#include <memory> + +#include "lldb/API/SBDefines.h" + +namespace lldb_private { +class AddressRangeListImpl; +} + +namespace lldb { + +class LLDB_API SBAddressRangeList { +public: + SBAddressRangeList(); + + SBAddressRangeList(const lldb::SBAddressRangeList &rhs); + + ~SBAddressRangeList(); + + const lldb::SBAddressRangeList & + operator=(const lldb::SBAddressRangeList &rhs); + + uint32_t GetSize() const; + + void Clear(); + + SBAddressRange GetAddressRangeAtIndex(uint64_t idx); + + void Append(const lldb::SBAddressRange &addr_range); + + void Append(const lldb::SBAddressRangeList &addr_range_list); + + bool GetDescription(lldb::SBStream &description, const SBTarget &target); + +private: + friend class SBBlock; + friend class SBProcess; + + lldb_private::AddressRangeListImpl &ref() const; + + std::unique_ptr<lldb_private::AddressRangeListImpl> m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_API_SBADDRESSRANGELIST_H diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBBlock.h b/contrib/llvm-project/lldb/include/lldb/API/SBBlock.h index 2570099f7652..de4bb22be269 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBBlock.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBBlock.h @@ -9,6 +9,8 @@ #ifndef LLDB_API_SBBLOCK_H #define LLDB_API_SBBLOCK_H +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBTarget.h" @@ -52,6 +54,8 @@ public: lldb::SBAddress GetRangeEndAddress(uint32_t idx); + lldb::SBAddressRangeList GetRanges(); + uint32_t GetRangeIndexForBlockAddress(lldb::SBAddress block_addr); lldb::SBValueList GetVariables(lldb::SBFrame &frame, bool arguments, diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBBreakpointName.h b/contrib/llvm-project/lldb/include/lldb/API/SBBreakpointName.h index 27ca1a3f6bfa..838c66385bd1 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBBreakpointName.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBBreakpointName.h @@ -1,4 +1,4 @@ -//===-- SBBreakpointName.h ------------------------------------------*- C++ -*-===// +//===-- SBBreakpointName.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. diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreter.h b/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreter.h index b7f5b3bf3396..b7e39b785861 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreter.h @@ -13,6 +13,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBDefines.h" +#include "lldb/API/SBStructuredData.h" namespace lldb_private { class CommandPluginInterfaceImplementation; @@ -264,11 +265,9 @@ public: // Catch commands before they execute by registering a callback that will get // called when the command gets executed. This allows GUI or command line // interfaces to intercept a command and stop it from happening -#ifndef SWIG bool SetCommandOverrideCallback(const char *command_name, lldb::CommandOverrideCallback callback, void *baton); -#endif /// Return true if the command interpreter is the active IO handler. /// @@ -315,6 +314,23 @@ public: /// and aliases. If successful, result->GetOutput has the full expansion. void ResolveCommand(const char *command_line, SBCommandReturnObject &result); + SBStructuredData GetStatistics(); + + /// Returns a list of handled commands, output and error. Each element in + /// the list is a dictionary with the following keys/values: + /// - "command" (string): The command that was given by the user. + /// - "commandName" (string): The name of the executed command. + /// - "commandArguments" (string): The arguments of the executed command. + /// - "output" (string): The output of the command. Empty ("") if no output. + /// - "error" (string): The error of the command. Empty ("") if no error. + /// - "durationInSeconds" (float): The time it took to execute the command. + /// - "timestampInEpochSeconds" (int): The timestamp when the command is + /// executed. + /// + /// Turn on settings `interpreter.save-transcript` for LLDB to populate + /// this list. Otherwise this list is empty. + SBStructuredData GetTranscript(); + protected: friend class lldb_private::CommandPluginInterfaceImplementation; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h b/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h index 69b969267e75..0f248c926d45 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h @@ -72,6 +72,14 @@ public: void SetSpawnThread(bool); + bool GetAllowRepeats() const; + + /// By default, RunCommandInterpreter will discard repeats if the + /// IOHandler being used is not interactive. Setting AllowRepeats to true + /// will override this behavior and always process empty lines in the input + /// as a repeat command. + void SetAllowRepeats(bool); + private: lldb_private::CommandInterpreterRunOptions *get() const; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBDebugger.h b/contrib/llvm-project/lldb/include/lldb/API/SBDebugger.h index 218113a7a391..84ea9c0f772e 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBDebugger.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBDebugger.h @@ -43,11 +43,12 @@ public: class LLDB_API SBDebugger { public: FLAGS_ANONYMOUS_ENUM(){ - eBroadcastBitProgress = (1 << 0), - eBroadcastBitWarning = (1 << 1), - eBroadcastBitError = (1 << 2), + eBroadcastBitProgress = lldb::DebuggerBroadcastBit::eBroadcastBitProgress, + eBroadcastBitWarning = lldb::DebuggerBroadcastBit::eBroadcastBitWarning, + eBroadcastBitError = lldb::DebuggerBroadcastBit::eBroadcastBitError, + eBroadcastBitProgressCategory = + lldb::DebuggerBroadcastBit::eBroadcastBitProgressCategory, }; - SBDebugger(); SBDebugger(const lldb::SBDebugger &rhs); @@ -56,6 +57,8 @@ public: static const char *GetBroadcasterClass(); + static bool SupportsLanguage(lldb::LanguageType language); + lldb::SBBroadcaster GetBroadcaster(); /// Get progress data from a SBEvent whose type is eBroadcastBitProgress. @@ -327,9 +330,22 @@ public: void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); + /// Clear all previously added callbacks and only add the given one. + LLDB_DEPRECATED_FIXME("Use AddDestroyCallback and RemoveDestroyCallback", + "AddDestroyCallback") void SetDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback, void *baton); + /// Add a callback for when the debugger is destroyed. Return a token, which + /// can be used to remove said callback. Multiple callbacks can be added by + /// calling this function multiple times, and will be invoked in FIFO order. + lldb::callback_token_t + AddDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback, + void *baton); + + /// Remove the specified callback. Return true if successful. + bool RemoveDestroyCallback(lldb::callback_token_t token); + #ifndef SWIG LLDB_DEPRECATED_FIXME("Use DispatchInput(const void *, size_t)", "DispatchInput(const void *, size_t)") diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBDefines.h b/contrib/llvm-project/lldb/include/lldb/API/SBDefines.h index 92d823fa1dfe..f42e2be558d2 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBDefines.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBDefines.h @@ -43,6 +43,8 @@ namespace lldb { class LLDB_API SBAddress; +class LLDB_API SBAddressRange; +class LLDB_API SBAddressRangeList; class LLDB_API SBAttachInfo; class LLDB_API SBBlock; class LLDB_API SBBreakpoint; @@ -59,6 +61,7 @@ class LLDB_API SBCommandPluginInterface; class LLDB_API SBCommandReturnObject; class LLDB_API SBCommunication; class LLDB_API SBCompileUnit; +class LLDB_API SBSaveCoreOptions; class LLDB_API SBData; class LLDB_API SBDebugger; class LLDB_API SBDeclaration; @@ -99,6 +102,7 @@ class LLDB_API SBReproducer; class LLDB_API SBScriptObject; class LLDB_API SBSection; class LLDB_API SBSourceManager; +class LLDB_API SBStatisticsOptions; class LLDB_API SBStream; class LLDB_API SBStringList; class LLDB_API SBStructuredData; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBError.h b/contrib/llvm-project/lldb/include/lldb/API/SBError.h index 1a720a479d9a..17f2c6c3027a 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBError.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBError.h @@ -77,6 +77,7 @@ protected: friend class SBBreakpointName; friend class SBCommandReturnObject; friend class SBCommunication; + friend class SBSaveCoreOptions; friend class SBData; friend class SBDebugger; friend class SBFile; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBEvent.h b/contrib/llvm-project/lldb/include/lldb/API/SBEvent.h index cc116766e85f..85b401ca8cc1 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBEvent.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBEvent.h @@ -15,6 +15,7 @@ #include <vector> namespace lldb_private { +class ScriptInterpreter; namespace python { class SWIGBridge; } @@ -73,11 +74,12 @@ protected: friend class SBThread; friend class SBWatchpoint; + friend class lldb_private::ScriptInterpreter; friend class lldb_private::python::SWIGBridge; SBEvent(lldb::EventSP &event_sp); - SBEvent(lldb_private::Event *event_sp); + SBEvent(lldb_private::Event *event); lldb::EventSP &GetSP() const; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBExpressionOptions.h b/contrib/llvm-project/lldb/include/lldb/API/SBExpressionOptions.h index e0ddfda5ba37..a9e929a4c0bd 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBExpressionOptions.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBExpressionOptions.h @@ -10,6 +10,7 @@ #define LLDB_API_SBEXPRESSIONOPTIONS_H #include "lldb/API/SBDefines.h" +#include "lldb/API/SBLanguages.h" #include <vector> @@ -67,6 +68,10 @@ public: void SetTrapExceptions(bool trap_exceptions = true); void SetLanguage(lldb::LanguageType language); + /// Set the language using a pair of language code and version as + /// defined by the DWARF 6 specification. + /// WARNING: These codes may change until DWARF 6 is finalized. + void SetLanguage(lldb::SBSourceLanguageName name, uint32_t version); #ifndef SWIG void SetCancelCallback(lldb::ExpressionCancelCallback callback, void *baton); diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBFileSpec.h b/contrib/llvm-project/lldb/include/lldb/API/SBFileSpec.h index beefa19ad7f3..36641843aabe 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBFileSpec.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBFileSpec.h @@ -78,6 +78,7 @@ private: friend class SBTarget; friend class SBThread; friend class SBTrace; + friend class SBSaveCoreOptions; SBFileSpec(const lldb_private::FileSpec &fspec); diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBFunction.h b/contrib/llvm-project/lldb/include/lldb/API/SBFunction.h index 71b372a818e4..df607fdc7ebf 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBFunction.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBFunction.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFUNCTION_H #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBInstructionList.h" @@ -44,6 +45,8 @@ public: lldb::SBAddress GetEndAddress(); + lldb::SBAddressRangeList GetRanges(); + const char *GetArgumentName(uint32_t arg_idx); uint32_t GetPrologueByteSize(); diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBLanguageRuntime.h b/contrib/llvm-project/lldb/include/lldb/API/SBLanguageRuntime.h index 38aac05d490c..011015ec4646 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBLanguageRuntime.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBLanguageRuntime.h @@ -18,6 +18,32 @@ public: static lldb::LanguageType GetLanguageTypeFromString(const char *string); static const char *GetNameForLanguageType(lldb::LanguageType language); + + /// Returns whether the given language is any version of C++. + static bool LanguageIsCPlusPlus(lldb::LanguageType language); + + /// Returns whether the given language is Obj-C or Obj-C++. + static bool LanguageIsObjC(lldb::LanguageType language); + + /// Returns whether the given language is any version of C, C++ or Obj-C. + static bool LanguageIsCFamily(lldb::LanguageType language); + + /// Returns whether the given language supports exception breakpoints on + /// throw statements. + static bool SupportsExceptionBreakpointsOnThrow(lldb::LanguageType language); + + /// Returns whether the given language supports exception breakpoints on + /// catch statements. + static bool SupportsExceptionBreakpointsOnCatch(lldb::LanguageType language); + + /// Returns the keyword used for throw statements in the given language, e.g. + /// Python uses \b raise. Returns \b nullptr if the language is not supported. + static const char *GetThrowKeywordForLanguage(lldb::LanguageType language); + + /// Returns the keyword used for catch statements in the given language, e.g. + /// Python uses \b except. Returns \b nullptr if the language is not + /// supported. + static const char *GetCatchKeywordForLanguage(lldb::LanguageType language); }; } // namespace lldb diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBLineEntry.h b/contrib/llvm-project/lldb/include/lldb/API/SBLineEntry.h index 7c2431ba3c8a..d70c4fac6ec7 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBLineEntry.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBLineEntry.h @@ -29,6 +29,9 @@ public: lldb::SBAddress GetEndAddress() const; + lldb::SBAddress + GetSameLineContiguousAddressRangeEnd(bool include_inlined_functions) const; + explicit operator bool() const; bool IsValid() const; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBProcess.h b/contrib/llvm-project/lldb/include/lldb/API/SBProcess.h index 8c1c81418f83..778be7958399 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBProcess.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBProcess.h @@ -209,6 +209,16 @@ public: lldb::addr_t ReadPointerFromMemory(addr_t addr, lldb::SBError &error); + lldb::SBAddressRangeList FindRangesInMemory(const void *buf, uint64_t size, + const SBAddressRangeList &ranges, + uint32_t alignment, + uint32_t max_matches, + SBError &error); + + lldb::addr_t FindInMemory(const void *buf, uint64_t size, + const SBAddressRange &range, uint32_t alignment, + SBError &error); + // Events static lldb::StateType GetStateFromEvent(const lldb::SBEvent &event); @@ -368,6 +378,12 @@ public: /// \param[in] file_name - The name of the file to save the core file to. lldb::SBError SaveCore(const char *file_name); + /// Save the state of the process with the desired settings + /// as defined in the options object. + /// + /// \param[in] options - The options to use when saving the core file. + lldb::SBError SaveCore(SBSaveCoreOptions &options); + /// Query the address load_addr and store the details of the memory /// region that contains it in the supplied SBMemoryRegionInfo object. /// To iterate over all memory regions use GetMemoryRegionList. @@ -398,6 +414,129 @@ public: /// valid. lldb::SBProcessInfo GetProcessInfo(); + /// Get the file specification for the core file that is currently being used + /// for the process. If the process is not loaded from a core file, then an + /// invalid file specification will be returned. + /// + /// \return + /// The path to the core file for this target or an invalid file spec if + /// the process isn't loaded from a core file. + lldb::SBFileSpec GetCoreFile(); + + /// \{ + /// \group Mask Address Methods + /// + /// \a type + /// All of the methods in this group take \a type argument + /// which is an AddressMaskType enum value. + /// There can be different address masks for code addresses and + /// data addresses, this argument can select which to get/set, + /// or to use when clearing non-addressable bits from an address. + /// This choice of mask can be important for example on AArch32 + /// systems. Where instructions where instructions start on even addresses, + /// the 0th bit may be used to indicate that a function is thumb code. On + /// such a target, the eAddressMaskTypeCode may clear the 0th bit from an + /// address to get the actual address Whereas eAddressMaskTypeData would not. + /// + /// \a addr_range + /// Many of the methods in this group take an \a addr_range argument + /// which is an AddressMaskRange enum value. + /// Needing to specify the address range is highly unusual, and the + /// default argument can be used in nearly all circumstances. + /// On some architectures (e.g., AArch64), it is possible to have + /// different page table setups for low and high memory, so different + /// numbers of bits relevant to addressing. It is possible to have + /// a program running in one half of memory and accessing the other + /// as heap, so we need to maintain two different sets of address masks + /// to debug this correctly. + + /// Get the current address mask that will be applied to addresses + /// before reading from memory. + /// + /// \param[in] type + /// See \ref Mask Address Methods description of this argument. + /// eAddressMaskTypeAny is often a suitable value when code and + /// data masks are the same on a given target. + /// + /// \param[in] addr_range + /// See \ref Mask Address Methods description of this argument. + /// This will default to eAddressMaskRangeLow which is the + /// only set of masks used normally. + /// + /// \return + /// The address mask currently in use. Bits which are not used + /// for addressing will be set to 1 in the mask. + lldb::addr_t GetAddressMask( + lldb::AddressMaskType type, + lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow); + + /// Set the current address mask that can be applied to addresses + /// before reading from memory. + /// + /// \param[in] type + /// See \ref Mask Address Methods description of this argument. + /// eAddressMaskTypeAll is often a suitable value when the + /// same mask is being set for both code and data. + /// + /// \param[in] mask + /// The address mask to set. Bits which are not used for addressing + /// should be set to 1 in the mask. + /// + /// \param[in] addr_range + /// See \ref Mask Address Methods description of this argument. + /// This will default to eAddressMaskRangeLow which is the + /// only set of masks used normally. + void SetAddressMask( + lldb::AddressMaskType type, lldb::addr_t mask, + lldb::AddressMaskRange addr_range = lldb::eAddressMaskRangeLow); + + /// Set the number of bits used for addressing in this Process. + /// + /// On Darwin and similar systems, the addressable bits are expressed + /// as the number of low order bits that are relevant to addressing, + /// instead of a more general address mask. + /// This method calculates the correct mask value for a given number + /// of low order addressable bits. + /// + /// \param[in] type + /// See \ref Mask Address Methods description of this argument. + /// eAddressMaskTypeAll is often a suitable value when the + /// same mask is being set for both code and data. + /// + /// \param[in] num_bits + /// Number of bits that are used for addressing. + /// For example, a value of 42 indicates that the low 42 bits + /// are relevant for addressing, and that higher-order bits may + /// be used for various metadata like pointer authentication, + /// Type Byte Ignore, etc. + /// + /// \param[in] addr_range + /// See \ref Mask Address Methods description of this argument. + /// This will default to eAddressMaskRangeLow which is the + /// only set of masks used normally. + void + SetAddressableBits(AddressMaskType type, uint32_t num_bits, + AddressMaskRange addr_range = lldb::eAddressMaskRangeLow); + + /// Clear the non-address bits of an \a addr value and return a + /// virtual address in memory. + /// + /// Bits that are not used in addressing may be used for other purposes; + /// pointer authentication, or metadata in the top byte, or the 0th bit + /// of armv7 code addresses to indicate arm/thumb are common examples. + /// + /// \param[in] addr + /// The address that should be cleared of non-address bits. + /// + /// \param[in] type + /// See \ref Mask Address Methods description of this argument. + /// eAddressMaskTypeAny is the default value, correct when it + /// is unknown if the address is a code or data address. + lldb::addr_t + FixAddress(lldb::addr_t addr, + lldb::AddressMaskType type = lldb::eAddressMaskTypeAny); + /// \} + /// Allocate memory within the process. /// /// This function will allocate memory in the process's address space. @@ -439,6 +578,8 @@ public: lldb::SBScriptObject GetScriptedImplementation(); + void GetStatus(SBStream &status); + protected: friend class SBAddress; friend class SBBreakpoint; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBSaveCoreOptions.h b/contrib/llvm-project/lldb/include/lldb/API/SBSaveCoreOptions.h new file mode 100644 index 000000000000..e77496bd3a4a --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/API/SBSaveCoreOptions.h @@ -0,0 +1,68 @@ +//===-- SBSaveCoreOptions.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_API_SBSAVECOREOPTIONS_H +#define LLDB_API_SBSAVECOREOPTIONS_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBSaveCoreOptions { +public: + SBSaveCoreOptions(); + SBSaveCoreOptions(const lldb::SBSaveCoreOptions &rhs); + ~SBSaveCoreOptions() = default; + + const SBSaveCoreOptions &operator=(const lldb::SBSaveCoreOptions &rhs); + + /// Set the plugin name. Supplying null or empty string will reset + /// the option. + /// + /// \param plugin Name of the object file plugin. + SBError SetPluginName(const char *plugin); + + /// Get the Core dump plugin name, if set. + /// + /// \return The name of the plugin, or null if not set. + const char *GetPluginName() const; + + /// Set the Core dump style. + /// + /// \param style The style of the core dump. + void SetStyle(lldb::SaveCoreStyle style); + + /// Get the Core dump style, if set. + /// + /// \return The core dump style, or undefined if not set. + lldb::SaveCoreStyle GetStyle() const; + + /// Set the output file path + /// + /// \param output_file a + /// \class SBFileSpec object that describes the output file. + void SetOutputFile(SBFileSpec output_file); + + /// Get the output file spec + /// + /// \return The output file spec. + SBFileSpec GetOutputFile() const; + + /// Reset all options. + void Clear(); + +protected: + friend class SBProcess; + lldb_private::SaveCoreOptions &ref() const; + +private: + std::unique_ptr<lldb_private::SaveCoreOptions> m_opaque_up; +}; // SBSaveCoreOptions +} // namespace lldb + +#endif // LLDB_API_SBSAVECOREOPTIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBStatisticsOptions.h b/contrib/llvm-project/lldb/include/lldb/API/SBStatisticsOptions.h new file mode 100644 index 000000000000..74bea03eff9c --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/API/SBStatisticsOptions.h @@ -0,0 +1,81 @@ +//===-- SBStatisticsOptions.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_API_SBSTATISTICSOPTIONS_H +#define LLDB_API_SBSTATISTICSOPTIONS_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +/// This class handles the verbosity when dumping statistics +class LLDB_API SBStatisticsOptions { +public: + SBStatisticsOptions(); + SBStatisticsOptions(const lldb::SBStatisticsOptions &rhs); + ~SBStatisticsOptions(); + + const SBStatisticsOptions &operator=(const lldb::SBStatisticsOptions &rhs); + + /// If true, dump only high-level summary statistics. Exclude details like + /// targets, modules, breakpoints, etc. This turns off `IncludeTargets`, + /// `IncludeModules` and `IncludeTranscript` by default. + /// + /// Defaults to false. + void SetSummaryOnly(bool b); + bool GetSummaryOnly(); + + /// If true, dump statistics for the targets, including breakpoints, + /// expression evaluations, frame variables, etc. + /// + /// Defaults to true, unless the `SummaryOnly` mode is enabled, in which case + /// this is turned off unless specified. + /// + /// If both `IncludeTargets` and `IncludeModules` are true, a list of module + /// identifiers will be added to the "targets" section. + void SetIncludeTargets(bool b); + bool GetIncludeTargets() const; + + /// If true, 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 `SummaryOnly` mode is enabled, in which case + /// this is turned off unless specified. + /// + /// If both `IncludeTargets` and `IncludeModules` are true, a list of module + /// identifiers will be added to the "targets" section. + void SetIncludeModules(bool b); + bool GetIncludeModules() const; + + /// If true and the setting `interpreter.save-transcript` is enabled, include + /// a JSON array with all commands the user and/or scripts executed during a + /// debug session. + /// + /// Defaults to true, unless the `SummaryOnly` mode is enabled, in which case + /// this is turned off unless specified. + void SetIncludeTranscript(bool b); + bool GetIncludeTranscript() const; + + /// If set to true, the debugger will load all debug info that is available + /// and report statistics on the total amount. If this is set to false, then + /// only report statistics on the currently loaded debug information. + /// This can avoid loading debug info from separate files just so it can + /// report the total size which can slow down statistics reporting. + void SetReportAllAvailableDebugInfo(bool b); + bool GetReportAllAvailableDebugInfo(); + +protected: + friend class SBTarget; + const lldb_private::StatisticsOptions &ref() const; + +private: + std::unique_ptr<lldb_private::StatisticsOptions> m_opaque_up; +}; +} // namespace lldb +#endif // LLDB_API_SBSTATISTICSOPTIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBStream.h b/contrib/llvm-project/lldb/include/lldb/API/SBStream.h index 0e33f05b6991..d230da6123fb 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBStream.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBStream.h @@ -13,6 +13,10 @@ #include "lldb/API/SBDefines.h" +namespace lldb_private { +class ScriptInterpreter; +} // namespace lldb_private + namespace lldb { class LLDB_API SBStream { @@ -62,6 +66,8 @@ public: protected: friend class SBAddress; + friend class SBAddressRange; + friend class SBAddressRangeList; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointLocation; @@ -101,6 +107,8 @@ protected: friend class SBValue; friend class SBWatchpoint; + friend class lldb_private::ScriptInterpreter; + lldb_private::Stream *operator->(); lldb_private::Stream *get(); diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBStructuredData.h b/contrib/llvm-project/lldb/include/lldb/API/SBStructuredData.h index 35d321eaa7b8..fc6e1ec95c7b 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBStructuredData.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBStructuredData.h @@ -122,6 +122,7 @@ protected: friend class SBTrace; friend class lldb_private::python::SWIGBridge; friend class lldb_private::lua::SWIGBridge; + friend class SBCommandInterpreter; SBStructuredData(const lldb_private::StructuredDataImpl &impl); diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBSymbolContextList.h b/contrib/llvm-project/lldb/include/lldb/API/SBSymbolContextList.h index 4026afc21357..95100d219df2 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBSymbolContextList.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBSymbolContextList.h @@ -44,6 +44,7 @@ public: protected: friend class SBModule; friend class SBTarget; + friend class SBCompileUnit; lldb_private::SymbolContextList *operator->() const; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBTarget.h b/contrib/llvm-project/lldb/include/lldb/API/SBTarget.h index 83087623088c..35c2ed9c20a2 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBTarget.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBTarget.h @@ -17,6 +17,7 @@ #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBLaunchInfo.h" +#include "lldb/API/SBStatisticsOptions.h" #include "lldb/API/SBSymbolContextList.h" #include "lldb/API/SBType.h" #include "lldb/API/SBValue.h" @@ -41,7 +42,8 @@ public: eBroadcastBitModulesLoaded = (1 << 1), eBroadcastBitModulesUnloaded = (1 << 2), eBroadcastBitWatchpointChanged = (1 << 3), - eBroadcastBitSymbolsLoaded = (1 << 4) + eBroadcastBitSymbolsLoaded = (1 << 4), + eBroadcastBitSymbolsChanged = (1 << 5), }; // Constructors @@ -90,6 +92,15 @@ public: /// A SBStructuredData with the statistics collected. lldb::SBStructuredData GetStatistics(); + /// Returns a dump of the collected statistics. + /// + /// \param[in] options + /// An objects object that contains all options for the statistics dumping. + /// + /// \return + /// A SBStructuredData with the statistics collected. + lldb::SBStructuredData GetStatistics(SBStatisticsOptions options); + /// Return the platform object associated with the target. /// /// After return, the platform object should be checked for @@ -868,6 +879,10 @@ public: uint32_t count, const char *flavor_string); + lldb::SBInstructionList ReadInstructions(lldb::SBAddress start_addr, + lldb::SBAddress end_addr, + const char *flavor_string); + lldb::SBInstructionList GetInstructions(lldb::SBAddress base_addr, const void *buf, size_t size); @@ -928,6 +943,7 @@ public: protected: friend class SBAddress; + friend class SBAddressRange; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointList; @@ -943,6 +959,7 @@ protected: friend class SBSection; friend class SBSourceManager; friend class SBSymbol; + friend class SBTypeStaticField; friend class SBValue; friend class SBVariablesOptions; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBType.h b/contrib/llvm-project/lldb/include/lldb/API/SBType.h index 9980fe121830..63ba91082d57 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBType.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBType.h @@ -107,6 +107,35 @@ protected: lldb::TypeMemberFunctionImplSP m_opaque_sp; }; +class LLDB_API SBTypeStaticField { +public: + SBTypeStaticField(); + + SBTypeStaticField(const lldb::SBTypeStaticField &rhs); + lldb::SBTypeStaticField &operator=(const lldb::SBTypeStaticField &rhs); + + ~SBTypeStaticField(); + + explicit operator bool() const; + + bool IsValid() const; + + const char *GetName(); + + const char *GetMangledName(); + + lldb::SBType GetType(); + + lldb::SBValue GetConstantValue(lldb::SBTarget target); + +protected: + friend class SBType; + + explicit SBTypeStaticField(lldb_private::CompilerDecl decl); + + std::unique_ptr<lldb_private::CompilerDecl> m_opaque_up; +}; + class SBType { public: SBType(); @@ -121,6 +150,8 @@ public: uint64_t GetByteSize(); + uint64_t GetByteAlign(); + bool IsPointerType(); bool IsReferenceType(); @@ -182,6 +213,8 @@ public: lldb::SBTypeMember GetVirtualBaseClassAtIndex(uint32_t idx); + lldb::SBTypeStaticField GetStaticFieldWithName(const char *name); + lldb::SBTypeEnumMemberList GetEnumMembers(); uint32_t GetNumberOfTemplateArguments(); @@ -242,6 +275,7 @@ protected: friend class SBTypeNameSpecifier; friend class SBTypeMember; friend class SBTypeMemberFunction; + friend class SBTypeStaticField; friend class SBTypeList; friend class SBValue; friend class SBWatchpoint; diff --git a/contrib/llvm-project/lldb/include/lldb/API/SBValue.h b/contrib/llvm-project/lldb/include/lldb/API/SBValue.h index bbcccaab51aa..bec816fb4518 100644 --- a/contrib/llvm-project/lldb/include/lldb/API/SBValue.h +++ b/contrib/llvm-project/lldb/include/lldb/API/SBValue.h @@ -68,6 +68,8 @@ public: uint64_t GetValueAsUnsigned(uint64_t fail_value = 0); + lldb::addr_t GetValueAsAddress(); + ValueType GetValueType(); // If you call this on a newly created ValueObject, it will always return @@ -87,6 +89,8 @@ public: lldb::SBValue GetNonSyntheticValue(); + lldb::SBValue GetSyntheticValue(); + lldb::DynamicValueType GetPreferDynamicValue(); void SetPreferDynamicValue(lldb::DynamicValueType use_dynamic); @@ -279,8 +283,22 @@ public: bool IsRuntimeSupportValue(); + /// Return the number of children of this variable. Note that for some + /// variables this operation can be expensive. If possible, prefer calling + /// GetNumChildren(max) with the maximum number of children you are interested + /// in. uint32_t GetNumChildren(); + /// Return the numer of children of this variable, with a hint that the + /// caller is interested in at most \a max children. Use this function to + /// avoid expensive child computations in some cases. For example, if you know + /// you will only ever display 100 elements, calling GetNumChildren(100) can + /// avoid enumerating all the other children. If the returned value is smaller + /// than \a max, then it represents the true number of children, otherwise it + /// indicates that their number is at least \a max. Do not assume the returned + /// number will always be less than or equal to \a max, as the implementation + /// may choose to return a larger (but still smaller than the actual number of + /// children) value. uint32_t GetNumChildren(uint32_t max); LLDB_DEPRECATED("SBValue::GetOpaqueType() is deprecated.") @@ -426,6 +444,7 @@ protected: friend class SBModule; friend class SBTarget; friend class SBThread; + friend class SBTypeStaticField; friend class SBTypeSummary; friend class SBValueList; diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/Breakpoint.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/Breakpoint.h index 8c4308ab0bc1..0b6bf593be37 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -637,7 +637,6 @@ private: Breakpoint(Target &new_target, const Breakpoint &bp_to_copy_from); // For Breakpoint only - bool m_being_created; bool m_hardware; // If this breakpoint is required to use a hardware breakpoint Target &m_target; // The target that holds this breakpoint. diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointID.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointID.h index a62323061b75..093966d0cf5d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointID.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointID.h @@ -26,6 +26,10 @@ public: virtual ~BreakpointID(); + bool operator==(BreakpointID rhs) const { + return m_break_id == rhs.m_break_id && m_location_id == rhs.m_location_id; + } + lldb::break_id_t GetBreakpointID() const { return m_break_id; } lldb::break_id_t GetLocationID() const { return m_location_id; } diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointIDList.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointIDList.h index 6c57d9bc5079..f2eaa60d9541 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointIDList.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointIDList.h @@ -42,10 +42,7 @@ public: bool AddBreakpointID(BreakpointID bp_id); - // TODO: This should take a const BreakpointID. - bool FindBreakpointID(BreakpointID &bp_id, size_t *position) const; - - bool FindBreakpointID(const char *bp_id, size_t *position) const; + bool Contains(BreakpointID bp_id) const; // Returns a pair consisting of the beginning and end of a breakpoint // ID range expression. If the input string is not a valid specification, diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointLocation.h index 2a4f9fc01bf3..cca00335bc3c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -313,6 +313,17 @@ private: void UndoBumpHitCount(); + /// Updates the thread ID internally. + /// + /// This method was created to handle actually mutating the thread ID + /// internally because SetThreadID broadcasts an event in addition to mutating + /// state. The constructor calls this instead of SetThreadID to avoid the + /// broadcast. + /// + /// \param[in] thread_id + /// The new thread ID. + void SetThreadIDInternal(lldb::tid_t thread_id); + // Constructors and Destructors // // Only the Breakpoint can make breakpoint locations, and it owns them. @@ -337,7 +348,6 @@ private: bool check_for_resolver = true); // Data members: - bool m_being_created; bool m_should_resolve_indirect_functions; bool m_is_reexported; bool m_is_indirect; diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointName.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointName.h index 22f017c77b26..c1c2ba110c39 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointName.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointName.h @@ -1,4 +1,4 @@ -//===-- BreakpointName.h --------------------------------------------*- C++ -*-===// +//===-- BreakpointName.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. diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h index 133fa8058637..16182e36d709 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h @@ -1,4 +1,4 @@ -//===-- BreakpointResolverScripted.h -----------------------------*- C++ -*-===// +//===-- BreakpointResolverScripted.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. diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/Watchpoint.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/Watchpoint.h index 22fdfd686c3f..16b83fbf7f70 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/Watchpoint.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/Watchpoint.h @@ -224,11 +224,8 @@ private: CompilerType m_type; Status m_error; // An error object describing errors associated with this // watchpoint. - WatchpointOptions - m_options; // Settable watchpoint options, which is a delegate to handle - // the callback machinery. - bool m_being_created; - + WatchpointOptions m_options; // Settable watchpoint options, which is a + // delegate to handle the callback machinery. std::unique_ptr<UserExpression> m_condition_up; // The condition to test. void SetID(lldb::watch_id_t id) { m_id = id; } diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointAlgorithms.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointAlgorithms.h new file mode 100644 index 000000000000..7d6d9f442b38 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointAlgorithms.h @@ -0,0 +1,106 @@ +//===-- WatchpointAlgorithms.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_BREAKPOINT_WATCHPOINTALGORITHMS_H +#define LLDB_BREAKPOINT_WATCHPOINTALGORITHMS_H + +#include "lldb/Breakpoint/WatchpointResource.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/lldb-private.h" + +#include <vector> + +namespace lldb_private { + +class WatchpointAlgorithms { + +public: + /// Convert a user's watchpoint request into an array of memory + /// regions, each region watched by one hardware watchpoint register. + /// + /// \param[in] addr + /// The start address specified by the user. + /// + /// \param[in] size + /// The number of bytes the user wants to watch. + /// + /// \param[in] read + /// True if we are watching for read accesses. + /// + /// \param[in] write + /// True if we are watching for write accesses. + /// \a read and \a write may both be true. + /// There is no "modify" style for WatchpointResources - + /// WatchpointResources are akin to the hardware watchpoint + /// registers which are either in terms of read or write. + /// "modify" distinction is done at the Watchpoint layer, where + /// we check the actual range of bytes the user requested. + /// + /// \param[in] supported_features + /// The bit flags in this parameter are set depending on which + /// WatchpointHardwareFeature enum values the current target supports. + /// The eWatchpointHardwareFeatureUnknown bit may be set if we + /// don't have specific information about what the remote stub + /// can support, and a reasonablec default will be used. + /// + /// \param[in] arch + /// The ArchSpec of the current Target. + /// + /// \return + /// A vector of WatchpointResourceSP's, one per hardware watchpoint + /// register needed. We may return more WatchpointResources than the + /// target can watch at once; if all resources cannot be set, the + /// watchpoint cannot be set. + static std::vector<lldb::WatchpointResourceSP> AtomizeWatchpointRequest( + lldb::addr_t addr, size_t size, bool read, bool write, + WatchpointHardwareFeature supported_features, ArchSpec &arch); + +protected: + struct Region { + lldb::addr_t addr; + size_t size; + }; + + /// Convert a user's watchpoint request into an array of Regions, + /// each of which can be watched by a single hardware watchpoint + /// that can watch power-of-2 size & aligned memory regions. + /// + /// This is the default algorithm if we have no further information; + /// most watchpoint implementations can be assumed to be able to watch up + /// to sizeof(void*) regions of memory, in power-of-2 sizes and alignments. + /// e.g. on a 64-bit target: 1, 2, 4, 8 or bytes with a single hardware + /// watchpoint register. + /// + /// \param[in] user_addr + /// The user's start address. + /// + /// \param[in] user_size + /// The user's specified byte length. + /// + /// \param[in] min_byte_size + /// The minimum byte size of the range of memory that can be watched + /// with one watchpoint register. + /// In most cases, this will be 1. AArch64 MASK watchpoints can + /// watch a minimum of 8 bytes (although Byte Address Select watchpoints + /// can watch 1 to pointer-size bytes in a pointer-size aligned granule). + /// + /// \param[in] max_byte_size + /// The maximum byte size supported for one watchpoint on this target. + /// + /// \param[in] address_byte_size + /// The address byte size on this target. + static std::vector<Region> PowerOf2Watchpoints(lldb::addr_t user_addr, + size_t user_size, + size_t min_byte_size, + size_t max_byte_size, + uint32_t address_byte_size); +}; + +} // namespace lldb_private + +#endif // LLDB_BREAKPOINT_WATCHPOINTALGORITHMS_H diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResource.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResource.h index 4b1d733850f1..070d84cff8f2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResource.h +++ b/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResource.h @@ -121,14 +121,6 @@ public: /// A copy of the Watchpoints which own this resource. WatchpointCollection CopyConstituentsList(); - // The ID of the WatchpointResource is set by the WatchpointResourceList - // when the Resource has been set in the inferior and is being added - // to the List, in an attempt to match the hardware watchpoint register - // ordering. If a Process can correctly identify the hardware watchpoint - // register index when it has created the Resource, it may initialize it - // before it is inserted in the WatchpointResourceList. - void SetID(lldb::wp_resource_id_t); - lldb::wp_resource_id_t GetID() const; bool Contains(lldb::addr_t addr); diff --git a/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResourceList.h b/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResourceList.h deleted file mode 100644 index 0e6c5fab8778..000000000000 --- a/contrib/llvm-project/lldb/include/lldb/Breakpoint/WatchpointResourceList.h +++ /dev/null @@ -1,145 +0,0 @@ -//===-- WatchpointResourceList.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_BREAKPOINT_WATCHPOINTRESOURCELIST_H -#define LLDB_BREAKPOINT_WATCHPOINTRESOURCELIST_H - -#include "lldb/Utility/Iterable.h" -#include "lldb/lldb-private.h" -#include "lldb/lldb-public.h" - -#include <mutex> -#include <vector> - -namespace lldb_private { - -class WatchpointResourceList { - -public: - WatchpointResourceList(); - - ~WatchpointResourceList(); - - /// Add a WatchpointResource to the list. - /// - /// \param[in] wp_res_sp - /// A shared pointer to a breakpoint site being added to the list. - /// - /// \return - /// The ID of the BreakpointSite in the list. - lldb::wp_resource_id_t Add(const lldb::WatchpointResourceSP &wp_res_sp); - - /// Removes the watchpoint resource given by \a id from this list. - /// - /// \param[in] id - /// The watchpoint resource to remove. - /// - /// \result - /// \b true if the watchpoint resource \a id was in the list. - bool Remove(lldb::wp_resource_id_t id); - - /// Removes the watchpoint resource containing address \a addr from this list. - /// - /// \param[in] addr - /// The address from which to remove a watchpoint resource. - /// - /// \result - /// \b true if \a addr had a watchpoint resource to remove from the list. - bool RemoveByAddress(lldb::addr_t addr); - - /// Returns a shared pointer to the watchpoint resource which contains - /// \a addr. - /// - /// \param[in] addr - /// The address to look for. - /// - /// \result - /// A shared pointer to the watchpoint resource. May contain a nullptr - /// pointer if no watchpoint site exists with a matching address. - lldb::WatchpointResourceSP FindByAddress(lldb::addr_t addr); - - /// Returns a shared pointer to the watchpoint resource which is owned - /// by \a wp_sp. - /// - /// \param[in] wp_sp - /// The WatchpointSP to look for. - /// - /// \result - /// A shared pointer to the watchpoint resource. May contain a nullptr - /// pointer if no watchpoint site exists - lldb::WatchpointResourceSP FindByWatchpointSP(lldb::WatchpointSP &wp_sp); - - /// Returns a shared pointer to the watchpoint resource which is owned - /// by \a wp. - /// - /// \param[in] wp - /// The Watchpoint to look for. - /// - /// \result - /// A shared pointer to the watchpoint resource. May contain a nullptr - /// pointer if no watchpoint site exists - lldb::WatchpointResourceSP - FindByWatchpoint(const lldb_private::Watchpoint *wp); - - /// Returns a shared pointer to the watchpoint resource which has hardware - /// index \a id. Some Process plugins may not have access to the actual - /// hardware watchpoint register number used for a WatchpointResource, so - /// the wp_resource_id_t may not be correctly tracking the target's wp - /// register target. - /// - /// \param[in] id - /// The hardware resource index to search for. - /// - /// \result - /// A shared pointer to the watchpoint resource. May contain a nullptr - /// pointer if no watchpoint site exists with a matching id. - lldb::WatchpointResourceSP FindByID(lldb::wp_resource_id_t id); - - /// - /// Get the number of WatchpointResources that are available. - /// - /// \return - /// The number of WatchpointResources that are stored in the - /// WatchpointResourceList. - uint32_t GetSize(); - - /// Get the WatchpointResource at a given index. - /// - /// \param [in] idx - /// The index of the resource. - /// \return - /// The WatchpointResource at that index number. - lldb::WatchpointResourceSP GetResourceAtIndex(uint32_t idx); - - typedef std::vector<lldb::WatchpointResourceSP> collection; - typedef LockingAdaptedIterable<collection, lldb::WatchpointResourceSP, - vector_adapter, std::mutex> - WatchpointResourceIterable; - - /// Iterate over the list of WatchpointResources. - /// - /// \return - /// An Iterable object which can be used to loop over the resources - /// that exist. - WatchpointResourceIterable Resources() { - return WatchpointResourceIterable(m_resources, m_mutex); - } - - /// Clear out the list of resources from the WatchpointResourceList - void Clear(); - - std::mutex &GetMutex(); - -private: - collection m_resources; - std::mutex m_mutex; -}; - -} // namespace lldb_private - -#endif // LLDB_BREAKPOINT_WATCHPOINTRESOURCELIST_H diff --git a/contrib/llvm-project/lldb/include/lldb/Core/AddressRange.h b/contrib/llvm-project/lldb/include/lldb/Core/AddressRange.h index 4a33c2d79587..68a3ad0edd2d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/AddressRange.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/AddressRange.h @@ -86,6 +86,8 @@ public: /// (LLDB_INVALID_ADDRESS) and a zero byte size. void Clear(); + bool IsValid() const; + /// Check if a section offset address is contained in this range. /// /// \param[in] so_addr @@ -236,12 +238,24 @@ public: /// The new size in bytes of this address range. void SetByteSize(lldb::addr_t byte_size) { m_byte_size = byte_size; } + bool GetDescription(Stream *s, Target *target) const; + + bool operator==(const AddressRange &rhs); + + bool operator!=(const AddressRange &rhs); + protected: // Member variables Address m_base_addr; ///< The section offset base address of this range. lldb::addr_t m_byte_size = 0; ///< The size in bytes of this address range. }; +// Forward-declarable wrapper. +class AddressRanges : public std::vector<lldb_private::AddressRange> { +public: + using std::vector<lldb_private::AddressRange>::vector; +}; + } // namespace lldb_private #endif // LLDB_CORE_ADDRESSRANGE_H diff --git a/contrib/llvm-project/lldb/include/lldb/Core/AddressRangeListImpl.h b/contrib/llvm-project/lldb/include/lldb/Core/AddressRangeListImpl.h new file mode 100644 index 000000000000..6742e6ead87d --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Core/AddressRangeListImpl.h @@ -0,0 +1,55 @@ +//===-- AddressRangeListImpl.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_CORE_ADDRESSRANGELISTIMPL_H +#define LLDB_CORE_ADDRESSRANGELISTIMPL_H + +#include "lldb/Core/AddressRange.h" +#include <cstddef> + +namespace lldb { +class SBAddressRangeList; +class SBBlock; +class SBProcess; +} + +namespace lldb_private { + +class AddressRangeListImpl { +public: + AddressRangeListImpl(); + + AddressRangeListImpl(const AddressRangeListImpl &rhs) = default; + + AddressRangeListImpl &operator=(const AddressRangeListImpl &rhs); + + size_t GetSize() const; + + void Reserve(size_t capacity); + + void Append(const AddressRange &sb_region); + + void Append(const AddressRangeListImpl &list); + + void Clear(); + + lldb_private::AddressRange GetAddressRangeAtIndex(size_t index); + +private: + friend class lldb::SBAddressRangeList; + friend class lldb::SBBlock; + friend class lldb::SBProcess; + + AddressRanges &ref(); + + AddressRanges m_ranges; +}; + +} // namespace lldb_private + +#endif // LLDB_CORE_ADDRESSRANGE_H diff --git a/contrib/llvm-project/lldb/include/lldb/Core/Debugger.h b/contrib/llvm-project/lldb/include/lldb/Core/Debugger.h index c6d603ca5dcd..a72c2596cc2c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/Debugger.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/Debugger.h @@ -40,6 +40,7 @@ #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DynamicLibrary.h" @@ -52,7 +53,7 @@ namespace llvm { class raw_ostream; -class ThreadPool; +class ThreadPoolInterface; } // namespace llvm namespace lldb_private { @@ -78,17 +79,9 @@ class Debugger : public std::enable_shared_from_this<Debugger>, public UserID, public Properties { public: - /// Broadcaster event bits definitions. - enum { - eBroadcastBitProgress = (1 << 0), - eBroadcastBitWarning = (1 << 1), - eBroadcastBitError = (1 << 2), - eBroadcastSymbolChange = (1 << 3), - }; - using DebuggerList = std::vector<lldb::DebuggerSP>; - static ConstString GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); /// Get the public broadcaster for this debugger. Broadcaster &GetBroadcaster() { return m_broadcaster; } @@ -498,8 +491,8 @@ public: return m_broadcaster_manager_sp; } - /// Shared thread poll. Use only with ThreadPoolTaskGroup. - static llvm::ThreadPool &GetThreadPool(); + /// Shared thread pool. Use only with ThreadPoolTaskGroup. + static llvm::ThreadPoolInterface &GetThreadPool(); /// Report warning events. /// @@ -567,10 +560,25 @@ public: static void ReportSymbolChange(const ModuleSpec &module_spec); + /// DEPRECATED: We used to only support one Destroy callback. Now that we + /// support Add and Remove, you should only remove callbacks that you added. + /// Use Add and Remove instead. + /// + /// Clear all previously added callbacks and only add the given one. void SetDestroyCallback(lldb_private::DebuggerDestroyCallback destroy_callback, void *baton); + /// Add a callback for when the debugger is destroyed. Return a token, which + /// can be used to remove said callback. Multiple callbacks can be added by + /// calling this function multiple times, and will be invoked in FIFO order. + lldb::callback_token_t + AddDestroyCallback(lldb_private::DebuggerDestroyCallback destroy_callback, + void *baton); + + /// Remove the specified callback. Return true if successful. + bool RemoveDestroyCallback(lldb::callback_token_t token); + /// Manually start the global event handler thread. It is useful to plugins /// that directly use the \a lldb_private namespace and want to use the /// debugger's default event handler thread instead of defining their own. @@ -592,6 +600,7 @@ protected: friend class CommandInterpreter; friend class REPL; friend class Progress; + friend class ProgressManager; /// Report progress events. /// @@ -622,13 +631,13 @@ protected: /// debugger identifier that this progress should be delivered to. If this /// optional parameter does not have a value, the progress will be /// delivered to all debuggers. - static void ReportProgress(uint64_t progress_id, std::string title, - std::string details, uint64_t completed, - uint64_t total, - std::optional<lldb::user_id_t> debugger_id); + static void + ReportProgress(uint64_t progress_id, std::string title, std::string details, + uint64_t completed, uint64_t total, + std::optional<lldb::user_id_t> debugger_id, + uint32_t progress_category_bit = lldb::eBroadcastBitProgress); - static void ReportDiagnosticImpl(DiagnosticEventData::Type type, - std::string message, + static void ReportDiagnosticImpl(lldb::Severity severity, std::string message, std::optional<lldb::user_id_t> debugger_id, std::once_flag *once); @@ -728,8 +737,19 @@ protected: lldb::TargetSP m_dummy_target_sp; Diagnostics::CallbackID m_diagnostics_callback_id; - lldb_private::DebuggerDestroyCallback m_destroy_callback = nullptr; - void *m_destroy_callback_baton = nullptr; + std::mutex m_destroy_callback_mutex; + lldb::callback_token_t m_destroy_callback_next_token = 0; + struct DestroyCallbackInfo { + DestroyCallbackInfo() {} + DestroyCallbackInfo(lldb::callback_token_t token, + lldb_private::DebuggerDestroyCallback callback, + void *baton) + : token(token), callback(callback), baton(baton) {} + lldb::callback_token_t token; + lldb_private::DebuggerDestroyCallback callback; + void *baton; + }; + llvm::SmallVector<DestroyCallbackInfo, 2> m_destroy_callbacks; uint32_t m_interrupt_requested = 0; ///< Tracks interrupt requests std::mutex m_interrupt_mutex; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/DebuggerEvents.h b/contrib/llvm-project/lldb/include/lldb/Core/DebuggerEvents.h index 4a27766e94e3..49a4ecf8e537 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/DebuggerEvents.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/DebuggerEvents.h @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Progress.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/StructuredData.h" @@ -39,7 +40,7 @@ public: GetAsStructuredData(const Event *event_ptr); uint64_t GetID() const { return m_id; } - bool IsFinite() const { return m_total != UINT64_MAX; } + bool IsFinite() const { return m_total != Progress::kNonDeterministicTotal; } uint64_t GetCompleted() const { return m_completed; } uint64_t GetTotal() const { return m_total; } std::string GetMessage() const { @@ -75,19 +76,15 @@ private: class DiagnosticEventData : public EventData { public: - enum class Type { - Info, - Warning, - Error, - }; - DiagnosticEventData(Type type, std::string message, bool debugger_specific) - : m_message(std::move(message)), m_type(type), + DiagnosticEventData(lldb::Severity severity, std::string message, + bool debugger_specific) + : m_message(std::move(message)), m_severity(severity), m_debugger_specific(debugger_specific) {} ~DiagnosticEventData() override = default; const std::string &GetMessage() const { return m_message; } bool IsDebuggerSpecific() const { return m_debugger_specific; } - Type GetType() const { return m_type; } + lldb::Severity GetSeverity() const { return m_severity; } llvm::StringRef GetPrefix() const; @@ -104,7 +101,7 @@ public: protected: std::string m_message; - Type m_type; + lldb::Severity m_severity; const bool m_debugger_specific; DiagnosticEventData(const DiagnosticEventData &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h index 885ac1bb4a7e..21969aed03c2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/Disassembler.h @@ -538,7 +538,7 @@ protected: ElideMixedSourceAndDisassemblyLine(const ExecutionContext &exe_ctx, const SymbolContext &sc, LineEntry &line) { SourceLine sl; - sl.file = line.file; + sl.file = line.GetFile(); sl.line = line.line; sl.column = line.column; return ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, sl); @@ -547,7 +547,6 @@ protected: // Classes that inherit from Disassembler can see and modify these ArchSpec m_arch; InstructionList m_instruction_list; - lldb::addr_t m_base_addr; std::string m_flavor; private: diff --git a/contrib/llvm-project/lldb/include/lldb/Core/EmulateInstruction.h b/contrib/llvm-project/lldb/include/lldb/Core/EmulateInstruction.h index 93c16537adba..b459476883fc 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/EmulateInstruction.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/EmulateInstruction.h @@ -369,6 +369,8 @@ public: virtual bool ReadInstruction() = 0; + virtual std::optional<uint32_t> GetLastInstrSize() { return std::nullopt; } + virtual bool EvaluateInstruction(uint32_t evaluate_options) = 0; virtual InstructionCondition GetInstructionCondition() { diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ModuleList.h b/contrib/llvm-project/lldb/include/lldb/Core/ModuleList.h index d78f7c5ef3f7..43d931a84474 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ModuleList.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ModuleList.h @@ -47,6 +47,26 @@ class UUID; class VariableList; struct ModuleFunctionSearchOptions; +static constexpr OptionEnumValueElement g_auto_download_enum_values[] = { + { + lldb::eSymbolDownloadOff, + "off", + "Disable automatically downloading symbols.", + }, + { + lldb::eSymbolDownloadBackground, + "background", + "Download symbols in the background for images as they appear in the " + "backtrace.", + }, + { + lldb::eSymbolDownloadForeground, + "foreground", + "Download symbols in the foreground for images as they appear in the " + "backtrace.", + }, +}; + class ModuleListProperties : public Properties { mutable llvm::sys::RWMutex m_symlink_paths_mutex; PathMappingList m_symlink_paths; @@ -60,7 +80,6 @@ public: bool SetClangModulesCachePath(const FileSpec &path); bool GetEnableExternalLookup() const; bool SetEnableExternalLookup(bool new_value); - bool GetEnableBackgroundLookup() const; bool GetEnableLLDBIndexCache() const; bool SetEnableLLDBIndexCache(bool new_value); uint64_t GetLLDBIndexCacheMaxByteSize(); @@ -71,6 +90,8 @@ public: bool GetLoadSymbolOnDemand(); + lldb::SymbolDownload GetSymbolAutoDownload() const; + PathMappingList GetSymlinkMappings() const; }; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/PluginManager.h b/contrib/llvm-project/lldb/include/lldb/Core/PluginManager.h index f2296e292023..38a291d9f0af 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/PluginManager.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/PluginManager.h @@ -178,6 +178,8 @@ public: static bool UnregisterPlugin(ObjectFileCreateInstance create_callback); + static bool IsRegisteredObjectFilePluginName(llvm::StringRef name); + static ObjectFileCreateInstance GetObjectFileCreateCallbackAtIndex(uint32_t idx); @@ -191,9 +193,7 @@ public: GetObjectFileCreateMemoryCallbackForPluginName(llvm::StringRef name); static Status SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name); + const lldb_private::SaveCoreOptions &core_options); // ObjectContainer static bool RegisterPlugin( diff --git a/contrib/llvm-project/lldb/include/lldb/Core/Progress.h b/contrib/llvm-project/lldb/include/lldb/Core/Progress.h index 65d30ea25cd2..421e435a9e68 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/Progress.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/Progress.h @@ -9,9 +9,12 @@ #ifndef LLDB_CORE_PROGRESS_H #define LLDB_CORE_PROGRESS_H -#include "lldb/Utility/ConstString.h" +#include "lldb/Host/Alarm.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" +#include "llvm/ADT/StringMap.h" #include <atomic> +#include <cstdint> #include <mutex> #include <optional> @@ -39,8 +42,8 @@ namespace lldb_private { /// uint64_t total, /// void *baton); /// -/// This callback will always initially be called with "completed" set to zero -/// and "total" set to the total amount specified in the contructor. This is +/// This callback will always initially be called with \a completed set to zero +/// and \a total set to the total amount specified in the constructor. This is /// considered the progress start event. As Progress::Increment() is called, /// the callback will be called as long as the Progress::m_completed has not /// yet exceeded the Progress::m_total. When the callback is called with @@ -49,7 +52,7 @@ namespace lldb_private { /// Progress::m_total, then this is considered a progress update event. /// /// This callback will be called in the destructor if Progress::m_completed is -/// not equal to Progress::m_total with the "completed" set to +/// not equal to Progress::m_total with the \a completed set to /// Progress::m_total. This ensures we always send a progress completed update /// even if the user does not. @@ -59,10 +62,17 @@ public: /// /// The constructor will create a unique progress reporting object and /// immediately send out a progress update by calling the installed callback - /// with completed set to zero out of the specified total. + /// with \a completed set to zero out of the specified total. /// /// @param [in] title The title of this progress activity. /// + /// @param [in] details Specific information about what the progress report + /// is currently working on. Although not required, if the progress report is + /// updated with Progress::Increment() then this field will be overwritten + /// with the new set of details passed into that function, and the details + /// passed initially will act as an "item 0" for the total set of + /// items being reported on. + /// /// @param [in] total The total units of work to be done if specified, if /// set to std::nullopt then an indeterminate progress indicator should be /// displayed. @@ -76,11 +86,11 @@ public: /// Destroy the progress object. /// /// If the progress has not yet sent a completion update, the destructor - /// will send out a notification where the completed == m_total. This ensures - /// that we always send out a progress complete notification. + /// will send out a notification where the \a completed == m_total. This + /// ensures that we always send out a progress complete notification. ~Progress(); - /// Increment the progress and send a notification to the intalled callback. + /// Increment the progress and send a notification to the installed callback. /// /// If incrementing ends up exceeding m_total, m_completed will be updated /// to match m_total and no subsequent progress notifications will be sent. @@ -93,27 +103,93 @@ public: void Increment(uint64_t amount = 1, std::optional<std::string> updated_detail = {}); + /// Used to indicate a non-deterministic progress report + static constexpr uint64_t kNonDeterministicTotal = UINT64_MAX; + + /// Data belonging to this Progress event that is used for bookkeeping by + /// ProgressManager. + struct ProgressData { + /// The title of the progress activity, also used as a category. + std::string title; + /// A unique integer identifier for progress reporting. + uint64_t progress_id; + /// The optional debugger ID to report progress to. If this has no value + /// then all debuggers will receive this event. + std::optional<lldb::user_id_t> debugger_id; + }; + private: void ReportProgress(); static std::atomic<uint64_t> g_id; - /// The title of the progress activity. - std::string m_title; + /// More specific information about the current file being displayed in the + /// report. std::string m_details; - std::mutex m_mutex; - /// A unique integer identifier for progress reporting. - const uint64_t m_id; /// How much work ([0...m_total]) that has been completed. uint64_t m_completed; /// Total amount of work, use a std::nullopt in the constructor for non /// deterministic progress. uint64_t m_total; - /// The optional debugger ID to report progress to. If this has no value then - /// all debuggers will receive this event. - std::optional<lldb::user_id_t> m_debugger_id; + std::mutex m_mutex; /// Set to true when progress has been reported where m_completed == m_total /// to ensure that we don't send progress updates after progress has /// completed. bool m_complete = false; + /// Data needed by the debugger to broadcast a progress event. + ProgressData m_progress_data; +}; + +/// A class used to group progress reports by category. This is done by using a +/// map that maintains a refcount of each category of progress reports that have +/// come in. Keeping track of progress reports this way will be done if a +/// debugger is listening to the eBroadcastBitProgressByCategory broadcast bit. +class ProgressManager { +public: + ProgressManager(); + ~ProgressManager(); + + /// Control the refcount of the progress report category as needed. + void Increment(const Progress::ProgressData &); + void Decrement(const Progress::ProgressData &); + + static void Initialize(); + static void Terminate(); + static bool Enabled(); + static ProgressManager &Instance(); + +protected: + enum class EventType { + Begin, + End, + }; + static void ReportProgress(const Progress::ProgressData &progress_data, + EventType type); + + static std::optional<ProgressManager> &InstanceImpl(); + + /// Helper function for reporting progress when the alarm in the corresponding + /// entry in the map expires. + void Expire(llvm::StringRef key); + + /// Entry used for bookkeeping. + struct Entry { + /// Reference count used for overlapping events. + uint64_t refcount = 0; + + /// Data used to emit progress events. + Progress::ProgressData data; + + /// Alarm handle used when the refcount reaches zero. + Alarm::Handle handle = Alarm::INVALID_HANDLE; + }; + + /// Map used for bookkeeping. + llvm::StringMap<Entry> m_entries; + + /// Mutex to provide the map. + std::mutex m_entries_mutex; + + /// Alarm instance to coalesce progress events. + Alarm m_alarm; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ThreadedCommunication.h b/contrib/llvm-project/lldb/include/lldb/Core/ThreadedCommunication.h index 7ebb77beb77f..24412b202793 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ThreadedCommunication.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ThreadedCommunication.h @@ -216,9 +216,9 @@ public: /// void SynchronizeWithReadThread(); - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObject.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObject.h index 4c0b0b2dae6c..93eb3e8f590f 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObject.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObject.h @@ -441,6 +441,30 @@ public: virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr); + /// If the current ValueObject is of an appropriate type, convert the + /// value to an APSInt and return that. Otherwise return an error. + llvm::Expected<llvm::APSInt> GetValueAsAPSInt(); + + /// If the current ValueObject is of an appropriate type, convert the + /// value to an APFloat and return that. Otherwise return an error. + llvm::Expected<llvm::APFloat> GetValueAsAPFloat(); + + /// If the current ValueObject is of an appropriate type, convert the + /// value to a boolean and return that. Otherwise return an error. + llvm::Expected<bool> GetValueAsBool(); + + /// Update an existing integer ValueObject with a new integer value. This + /// is only intended to be used with 'temporary' ValueObjects, i.e. ones that + /// are not associated with program variables. It does not update program + /// memory, registers, stack, etc. + void SetValueFromInteger(const llvm::APInt &value, Status &error); + + /// Update an existing integer ValueObject with an integer value created + /// frome 'new_val_sp'. This is only intended to be used with 'temporary' + /// ValueObjects, i.e. ones that are not associated with program variables. + /// It does not update program memory, registers, stack, etc. + void SetValueFromInteger(lldb::ValueObjectSP new_val_sp, Status &error); + virtual bool SetValueFromCString(const char *value_str, Status &error); /// Return the module associated with this value object in case the value is @@ -465,7 +489,7 @@ public: /// Returns a unique id for this ValueObject. lldb::user_id_t GetID() const { return m_id.GetID(); } - virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, + virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx, bool can_create = true); // The method always creates missing children in the path, if necessary. @@ -476,7 +500,13 @@ public: virtual size_t GetIndexOfChildWithName(llvm::StringRef name); - size_t GetNumChildren(uint32_t max = UINT32_MAX); + llvm::Expected<uint32_t> GetNumChildren(uint32_t max = UINT32_MAX); + /// Like \c GetNumChildren but returns 0 on error. You probably + /// shouldn't be using this function. It exists primarily to ease the + /// transition to more pervasive error handling while not all APIs + /// have been updated. + uint32_t GetNumChildrenIgnoringErrors(uint32_t max = UINT32_MAX); + bool HasChildren() { return GetNumChildrenIgnoringErrors() > 0; } const Value &GetValue() const { return m_value; } @@ -507,7 +537,7 @@ public: std::string &destination, const TypeSummaryOptions &options); - const char *GetObjectDescription(); + llvm::Expected<std::string> GetObjectDescription(); bool HasSpecialPrintableRepresentation( ValueObjectRepresentationStyle val_obj_display, @@ -612,6 +642,32 @@ public: virtual lldb::ValueObjectSP CastPointerType(const char *name, lldb::TypeSP &type_sp); + /// Return the target load address associated with this value object. + lldb::addr_t GetLoadAddress(); + + /// Take a ValueObject whose type is an inherited class, and cast it to + /// 'type', which should be one of its base classes. 'base_type_indices' + /// contains the indices of direct base classes on the path from the + /// ValueObject's current type to 'type' + llvm::Expected<lldb::ValueObjectSP> + CastDerivedToBaseType(CompilerType type, + const llvm::ArrayRef<uint32_t> &base_type_indices); + + /// Take a ValueObject whose type is a base class, and cast it to 'type', + /// which should be one of its derived classes. 'base_type_indices' + /// contains the indices of direct base classes on the path from the + /// ValueObject's current type to 'type' + llvm::Expected<lldb::ValueObjectSP> CastBaseToDerivedType(CompilerType type, + uint64_t offset); + + // Take a ValueObject that contains a scalar, enum or pointer type, and + // cast it to a "basic" type (integer, float or boolean). + lldb::ValueObjectSP CastToBasicType(CompilerType type); + + // Take a ValueObject that contain an integer, float or enum, and cast it + // to an enum. + lldb::ValueObjectSP CastToEnumType(CompilerType type); + /// If this object represents a C++ class with a vtable, return an object /// that represents the virtual function table. If the object isn't a class /// with a vtable, return a valid ValueObject with the error set correctly. @@ -638,9 +694,9 @@ public: virtual SymbolContextScope *GetSymbolContextScope(); - void Dump(Stream &s); + llvm::Error Dump(Stream &s); - void Dump(Stream &s, const DumpValueObjectOptions &options); + llvm::Error Dump(Stream &s, const DumpValueObjectOptions &options); static lldb::ValueObjectSP CreateValueObjectFromExpression(llvm::StringRef name, @@ -653,15 +709,41 @@ public: const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options); + /// Given an address either create a value object containing the value at + /// that address, or create a value object containing the address itself + /// (pointer value), depending on whether the parameter 'do_deref' is true or + /// false. static lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, - CompilerType type); + CompilerType type, bool do_deref = true); static lldb::ValueObjectSP CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); + /// Create a value object containing the given APInt value. + static lldb::ValueObjectSP CreateValueObjectFromAPInt(lldb::TargetSP target, + const llvm::APInt &v, + CompilerType type, + llvm::StringRef name); + + /// Create a value object containing the given APFloat value. + static lldb::ValueObjectSP + CreateValueObjectFromAPFloat(lldb::TargetSP target, const llvm::APFloat &v, + CompilerType type, llvm::StringRef name); + + /// Create a value object containing the given boolean value. + static lldb::ValueObjectSP CreateValueObjectFromBool(lldb::TargetSP target, + bool value, + llvm::StringRef name); + + /// Create a nullptr value object with the specified type (must be a + /// nullptr type). + static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target, + CompilerType type, + llvm::StringRef name); + lldb::ValueObjectSP Persist(); /// Returns true if this is a char* or a char[] if it is a char* and @@ -713,6 +795,10 @@ public: ClearUserVisibleData(eClearUserVisibleDataItemsSummary); } + void SetDerefValobj(ValueObject *deref) { m_deref_valobj = deref; } + + ValueObject *GetDerefValobj() { return m_deref_valobj; } + void SetValueFormat(lldb::TypeFormatImplSP format) { m_type_format_sp = std::move(format); ClearUserVisibleData(eClearUserVisibleDataItemsValue); @@ -791,7 +877,7 @@ protected: return (m_children.find(idx) != m_children.end()); } - ValueObject *GetChildAtIndex(size_t idx) { + ValueObject *GetChildAtIndex(uint32_t idx) { std::lock_guard<std::recursive_mutex> guard(m_mutex); const auto iter = m_children.find(idx); return ((iter == m_children.end()) ? nullptr : iter->second); @@ -953,14 +1039,18 @@ protected: /// Should only be called by ValueObject::GetChildAtIndex(). /// /// \return A ValueObject managed by this ValueObject's manager. - virtual ValueObject *CreateChildAtIndex(size_t idx, - bool synthetic_array_member, - int32_t synthetic_index); + virtual ValueObject *CreateChildAtIndex(size_t idx); + + /// Should only be called by ValueObject::GetSyntheticArrayMember(). + /// + /// \return A ValueObject managed by this ValueObject's manager. + virtual ValueObject *CreateSyntheticArrayMember(size_t idx); /// Should only be called by ValueObject::GetNumChildren(). - virtual size_t CalculateNumChildren(uint32_t max = UINT32_MAX) = 0; + virtual llvm::Expected<uint32_t> + CalculateNumChildren(uint32_t max = UINT32_MAX) = 0; - void SetNumChildren(size_t num_children); + void SetNumChildren(uint32_t num_children); void SetValueDidChange(bool value_changed) { m_flags.m_value_did_change = value_changed; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectCast.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectCast.h index fe053c12d9c3..ba25e166f326 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectCast.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectCast.h @@ -33,7 +33,7 @@ public: std::optional<uint64_t> GetByteSize() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectChild.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectChild.h index 46b14e6840f0..1f88e607cb57 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectChild.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectChild.h @@ -39,7 +39,7 @@ public: lldb::ValueType GetValueType() const override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; ConstString GetTypeName() override; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResult.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResult.h index d61df859bebc..d3b3362bd0e9 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResult.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResult.h @@ -67,7 +67,7 @@ public: lldb::ValueType GetValueType() const override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; ConstString GetTypeName() override; @@ -79,9 +79,6 @@ public: lldb::ValueObjectSP Dereference(Status &error) override; - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index) override; - lldb::ValueObjectSP GetSyntheticChildAtOffset( uint32_t offset, const CompilerType &type, bool can_create, ConstString name_const_str = ConstString()) override; @@ -151,6 +148,13 @@ private: ValueObjectConstResult(ExecutionContextScope *exe_scope, ValueObjectManager &manager, const Status &error); + ValueObject *CreateChildAtIndex(size_t idx) override { + return m_impl.CreateChildAtIndex(idx); + } + ValueObject *CreateSyntheticArrayMember(size_t idx) override { + return m_impl.CreateSyntheticArrayMember(idx); + } + ValueObjectConstResult(const ValueObjectConstResult &) = delete; const ValueObjectConstResult & operator=(const ValueObjectConstResult &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultCast.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultCast.h index efcbe0dc6a0b..911a08363b39 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultCast.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultCast.h @@ -35,9 +35,6 @@ public: lldb::ValueObjectSP Dereference(Status &error) override; - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index) override; - virtual CompilerType GetCompilerType() { return ValueObjectCast::GetCompilerType(); } @@ -61,6 +58,13 @@ private: friend class ValueObjectConstResult; friend class ValueObjectConstResultImpl; + ValueObject *CreateChildAtIndex(size_t idx) override { + return m_impl.CreateChildAtIndex(idx); + } + ValueObject *CreateSyntheticArrayMember(size_t idx) override { + return m_impl.CreateSyntheticArrayMember(idx); + } + ValueObjectConstResultCast(const ValueObjectConstResultCast &) = delete; const ValueObjectConstResultCast & operator=(const ValueObjectConstResultCast &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultChild.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultChild.h index 7e9da14e8e97..71a3c53befe7 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultChild.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultChild.h @@ -41,9 +41,6 @@ public: lldb::ValueObjectSP Dereference(Status &error) override; - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index) override; - virtual CompilerType GetCompilerType() { return ValueObjectChild::GetCompilerType(); } @@ -70,6 +67,13 @@ private: friend class ValueObjectConstResult; friend class ValueObjectConstResultImpl; + ValueObject *CreateChildAtIndex(size_t idx) override { + return m_impl.CreateChildAtIndex(idx); + } + ValueObject *CreateSyntheticArrayMember(size_t idx) override { + return m_impl.CreateSyntheticArrayMember(idx); + } + ValueObjectConstResultChild(const ValueObjectConstResultChild &) = delete; const ValueObjectConstResultChild & operator=(const ValueObjectConstResultChild &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultImpl.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultImpl.h index 5a7a079d3095..68ba8ae7fba2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultImpl.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectConstResultImpl.h @@ -38,8 +38,8 @@ public: lldb::ValueObjectSP Dereference(Status &error); - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index); + ValueObject *CreateChildAtIndex(size_t idx); + ValueObject *CreateSyntheticArrayMember(size_t idx); lldb::ValueObjectSP GetSyntheticChildAtOffset(uint32_t offset, const CompilerType &type, diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectDynamicValue.h index 2758b4e5bb56..82c20eee0cd4 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectDynamicValue.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectDynamicValue.h @@ -43,7 +43,7 @@ public: ConstString GetDisplayTypeName() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectMemory.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectMemory.h index 3c01df388d2e..a8fb0353d601 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectMemory.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectMemory.h @@ -47,7 +47,7 @@ public: ConstString GetDisplayTypeName() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectRegister.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectRegister.h index 2e47eee3d7f7..d948c663a4f8 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectRegister.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectRegister.h @@ -47,10 +47,7 @@ public: ConstString GetQualifiedTypeName() override; - size_t CalculateNumChildren(uint32_t max) override; - - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create = true) override; @@ -73,6 +70,11 @@ private: ValueObjectManager &manager, lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx); + ValueObject *CreateChildAtIndex(size_t idx) override; + ValueObject *CreateSyntheticArrayMember(size_t idx) override { + return nullptr; + } + // For ValueObject only ValueObjectRegisterSet(const ValueObjectRegisterSet &) = delete; const ValueObjectRegisterSet & @@ -95,7 +97,7 @@ public: ConstString GetTypeName() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; bool SetValueFromCString(const char *value_str, Status &error) override; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h index 67596232eafd..ca6d6c728005 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -47,11 +47,11 @@ public: bool MightHaveChildren() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx, + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx, bool can_create = true) override; lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVTable.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVTable.h index 217ff8d0d334..7087dcc1d1be 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVTable.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVTable.h @@ -64,10 +64,7 @@ public: std::optional<uint64_t> GetByteSize() override; - size_t CalculateNumChildren(uint32_t max) override; - - ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, - int32_t synthetic_index) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; @@ -95,6 +92,11 @@ protected: private: ValueObjectVTable(ValueObject &parent); + ValueObject *CreateChildAtIndex(size_t idx) override; + ValueObject *CreateSyntheticArrayMember(size_t idx) override { + return nullptr; + } + // For ValueObject only ValueObjectVTable(const ValueObjectVTable &) = delete; const ValueObjectVTable &operator=(const ValueObjectVTable &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVariable.h b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVariable.h index bba28ce567b2..db3847f14a0b 100644 --- a/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVariable.h +++ b/contrib/llvm-project/lldb/include/lldb/Core/ValueObjectVariable.h @@ -46,7 +46,7 @@ public: ConstString GetDisplayTypeName() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; lldb::ValueType GetValueType() const override; diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatCache.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatCache.h index e75aaee1a7bb..3f1baa26a5a5 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatCache.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatCache.h @@ -45,15 +45,12 @@ private: void Set(lldb::TypeSummaryImplSP); void Set(lldb::SyntheticChildrenSP); }; - typedef std::map<ConstString, Entry> CacheMap; - CacheMap m_map; + std::map<ConstString, Entry> m_entries; std::recursive_mutex m_mutex; uint64_t m_cache_hits = 0; uint64_t m_cache_misses = 0; - Entry &GetEntry(ConstString type); - public: FormatCache() = default; diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatManager.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatManager.h index 986614f0c5e4..db2fe99c44ca 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatManager.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/FormatManager.h @@ -138,7 +138,7 @@ public: } static bool GetFormatFromCString(const char *format_cstr, - bool partial_match_ok, lldb::Format &format); + lldb::Format &format); static char GetFormatAsFormatChar(lldb::Format format); diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeCategoryMap.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeCategoryMap.h index efd01f321da9..b1981233378b 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeCategoryMap.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeCategoryMap.h @@ -94,12 +94,6 @@ private: MapType m_map; ActiveCategoriesList m_active_categories; - - MapType &map() { return m_map; } - - ActiveCategoriesList &active_list() { return m_active_categories; } - - std::recursive_mutex &mutex() { return m_map_mutex; } }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h index 41be9b7efda8..ede7442a02bf 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -38,25 +38,30 @@ public: virtual ~SyntheticChildrenFrontEnd() = default; - virtual size_t CalculateNumChildren() = 0; + virtual llvm::Expected<uint32_t> CalculateNumChildren() = 0; - virtual size_t CalculateNumChildren(uint32_t max) { + virtual llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) { auto count = CalculateNumChildren(); - return count <= max ? count : max; + if (!count) + return count; + return *count <= max ? *count : max; } - virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx) = 0; + uint32_t CalculateNumChildrenIgnoringErrors(uint32_t max = UINT32_MAX); + + virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) = 0; virtual size_t GetIndexOfChildWithName(ConstString name) = 0; - // this function is assumed to always succeed and it if fails, the front-end - // should know to deal with it in the correct way (most probably, by refusing - // to return any children) the return value of Update() should actually be - // interpreted as "ValueObjectSyntheticFilter cache is good/bad" if =true, - // ValueObjectSyntheticFilter is allowed to use the children it fetched - // previously and cached if =false, ValueObjectSyntheticFilter must throw - // away its cache, and query again for children - virtual bool Update() = 0; + /// This function is assumed to always succeed and if it fails, the front-end + /// should know to deal with it in the correct way (most probably, by refusing + /// to return any children). The return value of \ref Update should actually + /// be interpreted as "ValueObjectSyntheticFilter cache is good/bad". If this + /// function returns \ref lldb::ChildCacheState::eReuse, \ref + /// ValueObjectSyntheticFilter is allowed to use the children it fetched + /// previously and cached. Otherwise, \ref ValueObjectSyntheticFilter must + /// throw away its cache, and query again for children. + virtual lldb::ChildCacheState Update() = 0; // if this function returns false, then CalculateNumChildren() MUST return 0 // since UI frontends might validly decide not to inquire for children given @@ -108,15 +113,17 @@ public: ~SyntheticValueProviderFrontEnd() override = default; - size_t CalculateNumChildren() override { return 0; } + llvm::Expected<uint32_t> CalculateNumChildren() override { return 0; } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { return nullptr; } + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return nullptr; } size_t GetIndexOfChildWithName(ConstString name) override { return UINT32_MAX; } - bool Update() override { return false; } + lldb::ChildCacheState Update() override { + return lldb::ChildCacheState::eRefetch; + } bool MightHaveChildren() override { return false; } @@ -319,16 +326,20 @@ public: ~FrontEnd() override = default; - size_t CalculateNumChildren() override { return filter->GetCount(); } + llvm::Expected<uint32_t> CalculateNumChildren() override { + return filter->GetCount(); + } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { if (idx >= filter->GetCount()) return lldb::ValueObjectSP(); return m_backend.GetSyntheticExpressionPathChild( filter->GetExpressionPathAtIndex(idx), true); } - bool Update() override { return false; } + lldb::ChildCacheState Update() override { + return lldb::ChildCacheState::eRefetch; + } bool MightHaveChildren() override { return filter->GetCount() > 0; } @@ -421,13 +432,13 @@ public: bool IsValid(); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - size_t CalculateNumChildren(uint32_t max) override; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h index 2b3936eaa707..f9deb6ebf8d6 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -1,5 +1,4 @@ -//===-- ValueObjectPrinter.h ---------------------------------------*- C++ -//-*-===// +//===-- ValueObjectPrinter.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. @@ -21,15 +20,20 @@ namespace lldb_private { class ValueObjectPrinter { + /// The ValueObjectPrinter is a one-shot printer for ValueObjects. It + /// does not retain the ValueObject it is printing, that is the job of + /// its caller. It also doesn't attempt to track changes in the + /// ValueObject, e.g. changing synthetic child providers or changing + /// dynamic versus static versus synthetic settings. public: - ValueObjectPrinter(ValueObject *valobj, Stream *s); + ValueObjectPrinter(ValueObject &valobj, Stream *s); - ValueObjectPrinter(ValueObject *valobj, Stream *s, + ValueObjectPrinter(ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options); ~ValueObjectPrinter() = default; - bool PrintValueObject(); + llvm::Error PrintValueObject(); protected: typedef std::set<uint64_t> InstancePointersSet; @@ -37,25 +41,41 @@ protected: InstancePointersSetSP m_printed_instance_pointers; - // only this class (and subclasses, if any) should ever be concerned with the - // depth mechanism - ValueObjectPrinter(ValueObject *valobj, Stream *s, + /// Only this class (and subclasses, if any) should ever be + /// concerned with the depth mechanism. + ValueObjectPrinter(ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options, const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, InstancePointersSetSP printed_instance_pointers); - // we should actually be using delegating constructors here but some versions - // of GCC still have trouble with those - void Init(ValueObject *valobj, Stream *s, + /// Ee should actually be using delegating constructors here but + /// some versions of GCC still have trouble with those. + void Init(ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options, const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, InstancePointersSetSP printed_instance_pointers); - bool GetMostSpecializedValue(); - - const char *GetDescriptionForDisplay(); + /// Cache the ValueObject we are actually going to print. If this + /// ValueObject has a Dynamic type, we return that, if either the original + /// ValueObject or its Dynamic type has a Synthetic provider, return that. + /// This will never return an empty ValueObject, since we use the ValueObject + /// to carry errors. + /// Note, this gets called when making the printer object, and uses the + /// use dynamic and use synthetic settings of the ValueObject being printed, + /// so changes made to these settings won't affect already made + /// ValueObjectPrinters. SetupMostSpecializedValue(); + /// + /// Access the cached "most specialized value" - that is the one to use for + /// printing the value object's value. However, be sure to use + /// GetValueForChildGeneration when you are generating the children of this + /// value. + ValueObject &GetMostSpecializedValue(); + + void SetupMostSpecializedValue(); + + llvm::Expected<std::string> GetDescriptionForDisplay(); const char *GetRootNameForDisplay(); @@ -88,31 +108,32 @@ protected: bool PrintValueAndSummaryIfNeeded(bool &value_printed, bool &summary_printed); - bool PrintObjectDescriptionIfNeeded(bool value_printed, bool summary_printed); + llvm::Error PrintObjectDescriptionIfNeeded(bool value_printed, + bool summary_printed); bool ShouldPrintChildren(DumpValueObjectOptions::PointerDepth &curr_ptr_depth); bool ShouldExpandEmptyAggregates(); - ValueObject *GetValueObjectForChildrenGeneration(); + ValueObject &GetValueObjectForChildrenGeneration(); void PrintChildrenPreamble(bool value_printed, bool summary_printed); void PrintChildrenPostamble(bool print_dotdotdot); - lldb::ValueObjectSP GenerateChild(ValueObject *synth_valobj, size_t idx); + lldb::ValueObjectSP GenerateChild(ValueObject &synth_valobj, size_t idx); void PrintChild(lldb::ValueObjectSP child_sp, const DumpValueObjectOptions::PointerDepth &curr_ptr_depth); - uint32_t GetMaxNumChildrenToPrint(bool &print_dotdotdot); + llvm::Expected<uint32_t> GetMaxNumChildrenToPrint(bool &print_dotdotdot); void PrintChildren(bool value_printed, bool summary_printed, const DumpValueObjectOptions::PointerDepth &curr_ptr_depth); - void PrintChildrenIfNeeded(bool value_printed, bool summary_printed); + llvm::Error PrintChildrenIfNeeded(bool value_printed, bool summary_printed); bool PrintChildrenOneLiner(bool hide_names); @@ -121,8 +142,10 @@ protected: private: bool ShouldShowName() const; - ValueObject *m_orig_valobj; - ValueObject *m_valobj; + ValueObject &m_orig_valobj; + /// Cache the current "most specialized" value. Don't use this + /// directly, use GetMostSpecializedValue. + ValueObject *m_cached_valobj; Stream *m_stream; DumpValueObjectOptions m_options; Flags m_type_flags; diff --git a/contrib/llvm-project/lldb/include/lldb/DataFormatters/VectorIterator.h b/contrib/llvm-project/lldb/include/lldb/DataFormatters/VectorIterator.h index 3414298f255b..70bcf50ca1b1 100644 --- a/contrib/llvm-project/lldb/include/lldb/DataFormatters/VectorIterator.h +++ b/contrib/llvm-project/lldb/include/lldb/DataFormatters/VectorIterator.h @@ -24,11 +24,11 @@ public: VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, llvm::ArrayRef<ConstString> item_names); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpression.h b/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpression.h index 1d85308d1caa..e85ba464dea6 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpression.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpression.h @@ -132,13 +132,12 @@ public: /// \return /// True on success; false otherwise. If error_ptr is non-NULL, /// details of the failure are provided through it. - static bool Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, - lldb::ModuleSP module_sp, const DataExtractor &opcodes, - const plugin::dwarf::DWARFUnit *dwarf_cu, - const lldb::RegisterKind reg_set, - const Value *initial_value_ptr, - const Value *object_address_ptr, Value &result, - Status *error_ptr); + static llvm::Expected<Value> + Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, + lldb::ModuleSP module_sp, const DataExtractor &opcodes, + const plugin::dwarf::DWARFUnit *dwarf_cu, + const lldb::RegisterKind reg_set, const Value *initial_value_ptr, + const Value *object_address_ptr); static bool ParseDWARFLocationList(const plugin::dwarf::DWARFUnit *dwarf_cu, const DataExtractor &data, diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpressionList.h b/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpressionList.h index c2218ad4af0a..664c2603770f 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpressionList.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/DWARFExpressionList.h @@ -9,6 +9,7 @@ #ifndef LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H #define LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H +#include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Utility/RangeMap.h" #include "lldb/lldb-private.h" @@ -91,7 +92,7 @@ public: lldb::addr_t func_load_addr, lldb::addr_t file_addr, ABI *abi) const; - /// Dump all locaitons with each seperated by new line. + /// Dump all locaitons with each separated by new line. void GetDescription(Stream *s, lldb::DescriptionLevel level, ABI *abi) const; /// Search for a load address in the dwarf location list @@ -113,10 +114,11 @@ public: void SetModule(const lldb::ModuleSP &module) { m_module_wp = module; } - bool Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, - lldb::addr_t func_load_addr, const Value *initial_value_ptr, - const Value *object_address_ptr, Value &result, - Status *error_ptr) const; + llvm::Expected<Value> Evaluate(ExecutionContext *exe_ctx, + RegisterContext *reg_ctx, + lldb::addr_t func_load_addr, + const Value *initial_value_ptr, + const Value *object_address_ptr) const; private: // RangeDataVector requires a comparator for DWARFExpression, but it doesn't diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/DiagnosticManager.h b/contrib/llvm-project/lldb/include/lldb/Expression/DiagnosticManager.h index 06bf1d115f15..d49b7c99b114 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/DiagnosticManager.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/DiagnosticManager.h @@ -28,12 +28,6 @@ enum DiagnosticOrigin { eDiagnosticOriginLLVM }; -enum DiagnosticSeverity { - eDiagnosticSeverityError, - eDiagnosticSeverityWarning, - eDiagnosticSeverityRemark -}; - const uint32_t LLDB_INVALID_COMPILER_ID = UINT32_MAX; class Diagnostic { @@ -55,7 +49,7 @@ public: } } - Diagnostic(llvm::StringRef message, DiagnosticSeverity severity, + Diagnostic(llvm::StringRef message, lldb::Severity severity, DiagnosticOrigin origin, uint32_t compiler_id) : m_message(message), m_severity(severity), m_origin(origin), m_compiler_id(compiler_id) {} @@ -68,7 +62,7 @@ public: virtual bool HasFixIts() const { return false; } - DiagnosticSeverity GetSeverity() const { return m_severity; } + lldb::Severity GetSeverity() const { return m_severity; } uint32_t GetCompilerID() const { return m_compiler_id; } @@ -83,7 +77,7 @@ public: protected: std::string m_message; - DiagnosticSeverity m_severity; + lldb::Severity m_severity; DiagnosticOrigin m_origin; uint32_t m_compiler_id; // Compiler-specific diagnostic ID }; @@ -106,7 +100,7 @@ public: }); } - void AddDiagnostic(llvm::StringRef message, DiagnosticSeverity severity, + void AddDiagnostic(llvm::StringRef message, lldb::Severity severity, DiagnosticOrigin origin, uint32_t compiler_id = LLDB_INVALID_COMPILER_ID) { m_diagnostics.emplace_back( @@ -127,9 +121,9 @@ public: other.Clear(); } - size_t Printf(DiagnosticSeverity severity, const char *format, ...) + size_t Printf(lldb::Severity severity, const char *format, ...) __attribute__((format(printf, 3, 4))); - void PutString(DiagnosticSeverity severity, llvm::StringRef str); + void PutString(lldb::Severity severity, llvm::StringRef str); void AppendMessageToDiagnostic(llvm::StringRef str) { if (!m_diagnostics.empty()) diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/Expression.h b/contrib/llvm-project/lldb/include/lldb/Expression/Expression.h index 3e61d78828bb..356fe4b82ae4 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/Expression.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/Expression.h @@ -47,11 +47,8 @@ public: /// expression. Text() should contain the definition of this function. virtual const char *FunctionName() = 0; - /// Return the language that should be used when parsing. To use the - /// default, return eLanguageTypeUnknown. - virtual lldb::LanguageType Language() const { - return lldb::eLanguageTypeUnknown; - } + /// Return the language that should be used when parsing. + virtual SourceLanguage Language() const { return {}; } /// Return the Materializer that the parser should use when registering /// external values. diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/ExpressionParser.h b/contrib/llvm-project/lldb/include/lldb/Expression/ExpressionParser.h index ab5223c91553..2ef7e036909c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/ExpressionParser.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/ExpressionParser.h @@ -119,15 +119,36 @@ public: /// \return /// An error code indicating the success or failure of the operation. /// Test with Success(). - virtual Status + Status PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end, std::shared_ptr<IRExecutionUnit> &execution_unit_sp, ExecutionContext &exe_ctx, bool &can_interpret, - lldb_private::ExecutionPolicy execution_policy) = 0; + lldb_private::ExecutionPolicy execution_policy); bool GetGenerateDebugInfo() const { return m_generate_debug_info; } protected: + virtual Status + DoPrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end, + std::shared_ptr<IRExecutionUnit> &execution_unit_sp, + ExecutionContext &exe_ctx, bool &can_interpret, + lldb_private::ExecutionPolicy execution_policy) = 0; + +private: + /// Run all static initializers for an execution unit. + /// + /// \param[in] execution_unit_sp + /// The execution unit. + /// + /// \param[in] exe_ctx + /// The execution context to use when running them. Thread can't be null. + /// + /// \return + /// The error code indicating the + Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp, + ExecutionContext &exe_ctx); + +protected: Expression &m_expr; ///< The expression to be parsed bool m_generate_debug_info; }; diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/LLVMUserExpression.h b/contrib/llvm-project/lldb/include/lldb/Expression/LLVMUserExpression.h index 7d32d17dbf54..40b463933c07 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/LLVMUserExpression.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/LLVMUserExpression.h @@ -52,7 +52,7 @@ public: }; LLVMUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, - llvm::StringRef prefix, lldb::LanguageType language, + llvm::StringRef prefix, SourceLanguage language, ResultType desired_type, const EvaluateExpressionOptions &options); ~LLVMUserExpression() override; diff --git a/contrib/llvm-project/lldb/include/lldb/Expression/UserExpression.h b/contrib/llvm-project/lldb/include/lldb/Expression/UserExpression.h index b6cfeec7e899..b04d00b72e8f 100644 --- a/contrib/llvm-project/lldb/include/lldb/Expression/UserExpression.h +++ b/contrib/llvm-project/lldb/include/lldb/Expression/UserExpression.h @@ -56,7 +56,7 @@ public: /// If not eResultTypeAny, the type to use for the expression /// result. UserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, - llvm::StringRef prefix, lldb::LanguageType language, + llvm::StringRef prefix, SourceLanguage language, ResultType desired_type, const EvaluateExpressionOptions &options); @@ -202,7 +202,7 @@ public: virtual bool IsParseCacheable() { return true; } /// Return the language that should be used when parsing. To use the /// default, return eLanguageTypeUnknown. - lldb::LanguageType Language() const override { return m_language; } + SourceLanguage Language() const override { return m_language; } /// Return the desired result type of the function, or eResultTypeAny if /// indifferent. @@ -315,19 +315,22 @@ protected: lldb::ProcessSP &process_sp, lldb::StackFrameSP &frame_sp); - Address m_address; ///< The address the process is stopped in. - std::string m_expr_text; ///< The text of the expression, as typed by the user - std::string m_expr_prefix; ///< The text of the translation-level definitions, - ///as provided by the user - std::string m_fixed_text; ///< The text of the expression with fix-its applied - ///- this won't be set if the fixed text doesn't - ///parse. - lldb::LanguageType m_language; ///< The language to use when parsing - ///(eLanguageTypeUnknown means use defaults) - ResultType m_desired_type; ///< The type to coerce the expression's result to. - ///If eResultTypeAny, inferred from the expression. - EvaluateExpressionOptions - m_options; ///< Additional options provided by the user. + /// The address the process is stopped in. + Address m_address; + /// The text of the expression, as typed by the user. + std::string m_expr_text; + /// The text of the translation-level definitions, as provided by the user. + std::string m_expr_prefix; + /// The text of the expression with fix-its applied this won't be set if the + /// fixed text doesn't parse. + std::string m_fixed_text; + /// The language to use when parsing (unknown means use defaults). + SourceLanguage m_language; + /// The type to coerce the expression's result to. If eResultTypeAny, inferred + /// from the expression. + ResultType m_desired_type; + /// Additional options provided by the user. + EvaluateExpressionOptions m_options; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Host/Alarm.h b/contrib/llvm-project/lldb/include/lldb/Host/Alarm.h new file mode 100644 index 000000000000..23b1ff1af568 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Host/Alarm.h @@ -0,0 +1,115 @@ +//===-- Alarm.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_HOST_ALARM_H +#define LLDB_HOST_ALARM_H + +#include "lldb/Host/HostThread.h" +#include "lldb/lldb-types.h" +#include "llvm/Support/Chrono.h" + +#include <condition_variable> +#include <mutex> + +namespace lldb_private { + +/// \class Alarm abstraction that enables scheduling a callback function after a +/// specified timeout. Creating an alarm for a callback returns a Handle that +/// can be used to restart or cancel the alarm. +class Alarm { +public: + using Handle = uint64_t; + using Callback = std::function<void()>; + using TimePoint = llvm::sys::TimePoint<>; + using Duration = std::chrono::milliseconds; + + Alarm(Duration timeout, bool run_callback_on_exit = false); + ~Alarm(); + + /// Create an alarm for the given callback. The alarm will expire and the + /// callback will be called after the timeout. + /// + /// \returns + /// Handle which can be used to restart or cancel the alarm. + Handle Create(Callback callback); + + /// Restart the alarm for the given Handle. The alarm will expire and the + /// callback will be called after the timeout. + /// + /// \returns + /// True if the alarm was successfully restarted. False if there is no alarm + /// for the given Handle or the alarm already expired. + bool Restart(Handle handle); + + /// Cancel the alarm for the given Handle. The alarm and its handle will be + /// removed. + /// + /// \returns + /// True if the alarm was successfully canceled and the Handle removed. + /// False if there is no alarm for the given Handle or the alarm already + /// expired. + bool Cancel(Handle handle); + + static constexpr Handle INVALID_HANDLE = 0; + +private: + /// Helper functions to start, stop and check the status of the alarm thread. + /// @{ + void StartAlarmThread(); + void StopAlarmThread(); + bool AlarmThreadRunning(); + /// @} + + /// Return an unique, monotonically increasing handle. + static Handle GetNextUniqueHandle(); + + /// Helper to compute the next time the alarm thread needs to wake up. + TimePoint GetNextExpiration() const; + + /// Alarm entry. + struct Entry { + Handle handle; + Callback callback; + TimePoint expiration; + + Entry(Callback callback, TimePoint expiration); + bool operator==(const Entry &rhs) { return handle == rhs.handle; } + }; + + /// List of alarm entries. + std::vector<Entry> m_entries; + + /// Timeout between when an alarm is created and when it fires. + Duration m_timeout; + + /// The alarm thread. + /// @{ + HostThread m_alarm_thread; + lldb::thread_result_t AlarmThread(); + /// @} + + /// Synchronize access between the alarm thread and the main thread. + std::mutex m_alarm_mutex; + + /// Condition variable used to wake up the alarm thread. + std::condition_variable m_alarm_cv; + + /// Flag to signal the alarm thread that something changed and we need to + /// recompute the next alarm. + bool m_recompute_next_alarm = false; + + /// Flag to signal the alarm thread to exit. + bool m_exit = false; + + /// Flag to signal we should run all callbacks on exit. + bool m_run_callbacks_on_exit = false; +}; + +} // namespace lldb_private + +#endif // LLDB_HOST_ALARM_H diff --git a/contrib/llvm-project/lldb/include/lldb/Host/Editline.h b/contrib/llvm-project/lldb/include/lldb/Host/Editline.h index 9049b106f02a..0020f779891d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Host/Editline.h +++ b/contrib/llvm-project/lldb/include/lldb/Host/Editline.h @@ -367,7 +367,14 @@ private: void SetGetCharacterFunction(EditlineGetCharCallbackType callbackFn); #if LLDB_EDITLINE_USE_WCHAR +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif std::wstring_convert<std::codecvt_utf8<wchar_t>> m_utf8conv; +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif #endif ::EditLine *m_editline = nullptr; EditlineHistorySP m_history_sp; diff --git a/contrib/llvm-project/lldb/include/lldb/Host/Host.h b/contrib/llvm-project/lldb/include/lldb/Host/Host.h index 30549cd78914..9d0994978402 100644 --- a/contrib/llvm-project/lldb/include/lldb/Host/Host.h +++ b/contrib/llvm-project/lldb/include/lldb/Host/Host.h @@ -88,7 +88,7 @@ public: lldb::pid_t pid); /// Emit the given message to the operating system log. - static void SystemLog(llvm::StringRef message); + static void SystemLog(lldb::Severity severity, llvm::StringRef message); /// Get the process ID for the calling process. /// diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandInterpreter.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandInterpreter.h index 747188a15312..48f6618ab0e3 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -22,12 +22,14 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" #include <mutex> #include <optional> #include <stack> +#include <unordered_map> namespace lldb_private { class CommandInterpreter; @@ -91,15 +93,20 @@ public: /// \param[in] add_to_history /// If \b true add the commands to the command history. If \b false, don't /// add them. + /// \param[in] handle_repeats + /// If \b true then treat empty lines as repeat commands even if the + /// interpreter is non-interactive. CommandInterpreterRunOptions(LazyBool stop_on_continue, LazyBool stop_on_error, LazyBool stop_on_crash, LazyBool echo_commands, LazyBool echo_comments, LazyBool print_results, LazyBool print_errors, - LazyBool add_to_history) + LazyBool add_to_history, + LazyBool handle_repeats) : m_stop_on_continue(stop_on_continue), m_stop_on_error(stop_on_error), m_stop_on_crash(stop_on_crash), m_echo_commands(echo_commands), m_echo_comment_commands(echo_comments), m_print_results(print_results), - m_print_errors(print_errors), m_add_to_history(add_to_history) {} + m_print_errors(print_errors), m_add_to_history(add_to_history), + m_allow_repeats(handle_repeats) {} CommandInterpreterRunOptions() = default; @@ -181,6 +188,12 @@ public: m_spawn_thread = spawn_thread ? eLazyBoolYes : eLazyBoolNo; } + bool GetAllowRepeats() const { return DefaultToNo(m_allow_repeats); } + + void SetAllowRepeats(bool allow_repeats) { + m_allow_repeats = allow_repeats ? eLazyBoolYes : eLazyBoolNo; + } + LazyBool m_stop_on_continue = eLazyBoolCalculate; LazyBool m_stop_on_error = eLazyBoolCalculate; LazyBool m_stop_on_crash = eLazyBoolCalculate; @@ -191,6 +204,7 @@ public: LazyBool m_add_to_history = eLazyBoolCalculate; LazyBool m_auto_handle_events; LazyBool m_spawn_thread; + LazyBool m_allow_repeats = eLazyBoolCalculate; private: static bool DefaultToYes(LazyBool flag) { @@ -254,9 +268,9 @@ public: // These two functions fill out the Broadcaster interface: - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } @@ -559,6 +573,9 @@ public: bool GetPromptOnQuit() const; void SetPromptOnQuit(bool enable); + bool GetSaveTranscript() const; + void SetSaveTranscript(bool enable); + bool GetSaveSessionOnQuit() const; void SetSaveSessionOnQuit(bool enable); @@ -641,6 +658,13 @@ public: Status PreprocessCommand(std::string &command); Status PreprocessToken(std::string &token); + void IncreaseCommandUsage(const CommandObject &cmd_obj) { + ++m_command_usages[cmd_obj.GetCommandName()]; + } + + llvm::json::Value GetStatistics(); + const StructuredData::Array &GetTranscript() const; + protected: friend class Debugger; @@ -754,7 +778,28 @@ private: // If the driver is accepts custom exit codes for the 'quit' command. bool m_allow_exit_code = false; + /// Command usage statistics. + typedef llvm::StringMap<uint64_t> CommandUsageMap; + CommandUsageMap m_command_usages; + + /// Turn on settings `interpreter.save-transcript` for LLDB to populate + /// this stream. Otherwise this stream is empty. StreamString m_transcript_stream; + + /// Contains a list of handled commands and their details. Each element in + /// the list is a dictionary with the following keys/values: + /// - "command" (string): The command that was given by the user. + /// - "commandName" (string): The name of the executed command. + /// - "commandArguments" (string): The arguments of the executed command. + /// - "output" (string): The output of the command. Empty ("") if no output. + /// - "error" (string): The error of the command. Empty ("") if no error. + /// - "durationInSeconds" (float): The time it took to execute the command. + /// - "timestampInEpochSeconds" (int): The timestamp when the command is + /// executed. + /// + /// Turn on settings `interpreter.save-transcript` for LLDB to populate + /// this list. Otherwise this list is empty. + StructuredData::Array m_transcript; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandObject.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandObject.h index 7b427de0264f..d48dbcdd5a5d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandObject.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandObject.h @@ -207,6 +207,20 @@ public: static const ArgumentTableEntry * FindArgumentDataByType(lldb::CommandArgumentType arg_type); + // Sets the argument list for this command to one homogenous argument type, + // with the repeat specified. + void AddSimpleArgumentList( + lldb::CommandArgumentType arg_type, + ArgumentRepetitionType repetition_type = eArgRepeatPlain); + + // Helper function to set BP IDs or ID ranges as the command argument data + // for this command. + // This used to just populate an entry you could add to, but that was never + // used. If we ever need that we can take optional extra args here. + // Use this to define a simple argument list: + enum IDType { eBreakpointArgs = 0, eWatchpointArgs = 1 }; + void AddIDsArgumentData(IDType type); + int GetNumArgumentEntries(); CommandArgumentEntry *GetArgumentEntryAtIndex(int idx); @@ -224,7 +238,10 @@ public: void GetFormattedCommandArguments(Stream &str, uint32_t opt_set_mask = LLDB_OPT_SET_ALL); - bool IsPairType(ArgumentRepetitionType arg_repeat_type); + static bool IsPairType(ArgumentRepetitionType arg_repeat_type); + + static std::optional<ArgumentRepetitionType> + ArgRepetitionFromString(llvm::StringRef string); bool ParseOptions(Args &args, CommandReturnObject &result); @@ -239,6 +256,13 @@ public: /// The completion request that needs to be answered. virtual void HandleCompletion(CompletionRequest &request); + /// The default version handles argument definitions that have only one + /// argument type, and use one of the argument types that have an entry in + /// the CommonCompletions. Override this if you have a more complex + /// argument setup. + /// FIXME: we should be able to extend this to more complex argument + /// definitions provided we have completers for all the argument types. + /// /// The input array contains a parsed version of the line. /// /// We've constructed the map of options and their arguments as well if that @@ -248,7 +272,7 @@ public: /// The completion request that needs to be answered. virtual void HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) {} + OptionElementVector &opt_element_vector); bool HelpTextContainsWord(llvm::StringRef search_word, bool search_short_help = true, @@ -273,6 +297,10 @@ public: /// \param[in] current_command_args /// The command arguments. /// + /// \param[in] index + /// This is for internal use - it is how the completion request is tracked + /// in CommandObjectMultiword, and should otherwise be ignored. + /// /// \return /// std::nullopt if there is no special repeat command - it will use the /// current command line. @@ -381,12 +409,6 @@ protected: lldb_private::CommandOverrideCallbackWithResult m_command_override_callback; void *m_command_override_baton; bool m_is_user_command = false; - - // Helper function to populate IDs or ID ranges as the command argument data - // to the specified command argument entry. - static void AddIDsArgumentData(CommandArgumentEntry &arg, - lldb::CommandArgumentType ID, - lldb::CommandArgumentType IDRange); }; class CommandObjectParsed : public CommandObject { diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h index d0cf54c31ca7..b5e989633ea3 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/CommandOptionArgumentTable.h @@ -50,6 +50,11 @@ static constexpr OptionEnumValueElement g_sort_option_enumeration[] = { "name", "Sort output by symbol name.", }, + { + eSortOrderBySize, + "size", + "Sort output by symbol byte size.", + }, }; // Note that the negation in the argument name causes a slightly confusing @@ -243,7 +248,7 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = { { lldb::eArgTypeLogCategory, "log-category", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." }, { lldb::eArgTypeLogChannel, "log-channel", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." }, { lldb::eArgTypeMethod, "method", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A C++ method name." }, - { lldb::eArgTypeName, "name", lldb::eTypeCategoryNameCompletion, {}, { nullptr, false }, "Help text goes here." }, + { lldb::eArgTypeName, "name", lldb::eTypeCategoryNameCompletion, {}, { nullptr, false }, "The name of a type category." }, { lldb::eArgTypeNewPathPrefix, "new-path-prefix", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Help text goes here." }, { lldb::eArgTypeNumLines, "num-lines", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The number of lines to use." }, { lldb::eArgTypeNumberPerLine, "number-per-line", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The number of items per line to display." }, @@ -260,9 +265,9 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = { { lldb::eArgTypePythonFunction, "python-function", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a Python function." }, { lldb::eArgTypePythonScript, "python-script", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Source code written in Python." }, { lldb::eArgTypeQueueName, "queue-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of the thread queue." }, - { lldb::eArgTypeRegisterName, "register-name", lldb::CompletionType::eNoCompletion, {}, { RegisterNameHelpTextCallback, true }, nullptr }, + { lldb::eArgTypeRegisterName, "register-name", lldb::CompletionType::eRegisterCompletion, {}, { RegisterNameHelpTextCallback, true }, nullptr }, { lldb::eArgTypeRegularExpression, "regular-expression", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A POSIX-compliant extended regular expression." }, - { lldb::eArgTypeRunArgs, "run-args", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Arguments to be passed to the target program when it starts executing." }, + { lldb::eArgTypeRunArgs, "run-args", lldb::CompletionType::eDiskFileCompletion, {}, { nullptr, false }, "Arguments to be passed to the target program when it starts executing." }, { lldb::eArgTypeRunMode, "run-mode", lldb::CompletionType::eNoCompletion, g_running_mode, { nullptr, false }, "Help text goes here." }, { lldb::eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", lldb::CompletionType::eNoCompletion, g_script_synchro_type, { nullptr, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." }, { lldb::eArgTypeScriptLang, "script-language", lldb::CompletionType::eNoCompletion, g_script_option_enumeration, { nullptr, false }, "The scripting language to be used for script-based commands. Supported languages are python and lua." }, @@ -270,21 +275,21 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = { { lldb::eArgTypeSelector, "selector", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "An Objective-C selector name." }, { lldb::eArgTypeSettingIndex, "setting-index", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." }, { lldb::eArgTypeSettingKey, "setting-key", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." }, - { lldb::eArgTypeSettingPrefix, "setting-prefix", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" }, - { lldb::eArgTypeSettingVariableName, "setting-variable-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." }, - { lldb::eArgTypeShlibName, "shlib-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The name of a shared library." }, + { lldb::eArgTypeSettingPrefix, "setting-prefix", lldb::CompletionType::eSettingsNameCompletion, {}, { nullptr, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" }, + { lldb::eArgTypeSettingVariableName, "setting-variable-name", lldb::CompletionType::eSettingsNameCompletion, {}, { nullptr, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." }, + { lldb::eArgTypeShlibName, "shlib-name", lldb::CompletionType::eDiskFileCompletion, {}, { nullptr, false }, "The name of a shared library." }, { lldb::eArgTypeSourceFile, "source-file", lldb::eSourceFileCompletion, {}, { nullptr, false }, "The name of a source file.." }, { lldb::eArgTypeSortOrder, "sort-order", lldb::CompletionType::eNoCompletion, g_sort_option_enumeration, { nullptr, false }, "Specify a sort order when dumping lists." }, { lldb::eArgTypeStartAddress, "start-address", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Help text goes here." }, { lldb::eArgTypeSummaryString, "summary-string", lldb::CompletionType::eNoCompletion, {}, { SummaryStringHelpTextCallback, true }, nullptr }, { lldb::eArgTypeSymbol, "symbol", lldb::eSymbolCompletion, {}, { nullptr, false }, "Any symbol name (function name, variable, argument, etc.)" }, - { lldb::eArgTypeThreadID, "thread-id", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Thread ID number." }, - { lldb::eArgTypeThreadIndex, "thread-index", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Index into the process' list of threads." }, + { lldb::eArgTypeThreadID, "thread-id", lldb::CompletionType::eThreadIndexCompletion, {}, { nullptr, false }, "Thread ID number." }, + { lldb::eArgTypeThreadIndex, "thread-index", lldb::CompletionType::eThreadIndexCompletion, {}, { nullptr, false }, "Index into the process' list of threads." }, { lldb::eArgTypeThreadName, "thread-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The thread's name." }, { lldb::eArgTypeTypeName, "type-name", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A type name." }, { lldb::eArgTypeUnsignedInteger, "unsigned-integer", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "An unsigned integer." }, { lldb::eArgTypeUnixSignal, "unix-signal", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." }, - { lldb::eArgTypeVarName, "variable-name", lldb::CompletionType::eNoCompletion, {} ,{ nullptr, false }, "The name of a variable in your program." }, + { lldb::eArgTypeVarName, "variable-name", lldb::CompletionType::eVariablePathCompletion, {} ,{ nullptr, false }, "The name of a variable in your program." }, { lldb::eArgTypeValue, "value", lldb::CompletionType::eNoCompletion, g_dependents_enumeration, { nullptr, false }, "A value could be anything, depending on where and how it is used." }, { lldb::eArgTypeWidth, "width", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "Help text goes here." }, { lldb::eArgTypeNone, "none", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "No help available for this." }, @@ -302,8 +307,11 @@ static constexpr CommandObject::ArgumentTableEntry g_argument_table[] = { { lldb::eArgTypeRecognizerID, "frame-recognizer-id", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The ID for a stack frame recognizer." }, { lldb::eArgTypeConnectURL, "process-connect-url", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "A URL-style specification for a remote connection." }, { lldb::eArgTypeTargetID, "target-id", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The index ID for an lldb Target." }, - { lldb::eArgTypeStopHookID, "stop-hook-id", lldb::CompletionType::eNoCompletion, {}, { nullptr, false }, "The ID you receive when you create a stop-hook." }, + { lldb::eArgTypeStopHookID, "stop-hook-id", lldb::CompletionType::eStopHookIDCompletion, {}, { nullptr, false }, "The ID you receive when you create a stop-hook." }, { lldb::eArgTypeCompletionType, "completion-type", lldb::CompletionType::eNoCompletion, g_completion_type, { nullptr, false }, "The completion type to use when adding custom commands. If none is specified, the command won't use auto-completion." }, + { lldb::eArgTypeRemotePath, "remote-path", lldb::CompletionType::eRemoteDiskFileCompletion, {}, { nullptr, false }, "A path on the system managed by the current platform." }, + { lldb::eArgTypeRemoteFilename, "remote-filename", lldb::CompletionType::eRemoteDiskFileCompletion, {}, { nullptr, false }, "A file on the system managed by the current platform." }, + { lldb::eArgTypeModule, "module", lldb::CompletionType::eModuleCompletion, {}, { nullptr, false }, "The name of a module loaded into the current target." }, // clang-format on }; diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h index 9753a916243b..69504dbcda5d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedInterface.h @@ -10,7 +10,6 @@ #define LLDB_INTERPRETER_INTERFACES_SCRIPTEDINTERFACE_H #include "lldb/Core/StructuredDataImpl.h" -#include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/UnimplementedError.h" @@ -52,7 +51,8 @@ public: } template <typename T = StructuredData::ObjectSP> - bool CheckStructuredDataObject(llvm::StringRef caller, T obj, Status &error) { + static bool CheckStructuredDataObject(llvm::StringRef caller, T obj, + Status &error) { if (!obj) return ErrorWithMessage<bool>(caller, "Null Structured Data object", error); diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h new file mode 100644 index 000000000000..ee634d15f2a9 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h @@ -0,0 +1,38 @@ +//===-- ScriptedThreadPlanInterface.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_INTERPRETER_INTERFACES_SCRIPTEDTHREADPLANINTERFACE_H +#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDTHREADPLANINTERFACE_H + +#include "lldb/lldb-private.h" + +#include "ScriptedInterface.h" + +namespace lldb_private { +class ScriptedThreadPlanInterface : public ScriptedInterface { +public: + virtual llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, + lldb::ThreadPlanSP thread_plan_sp, + const StructuredDataImpl &args_sp) = 0; + + virtual llvm::Expected<bool> ExplainsStop(Event *event) { return true; } + + virtual llvm::Expected<bool> ShouldStop(Event *event) { return true; } + + virtual llvm::Expected<bool> IsStale() { return true; }; + + virtual lldb::StateType GetRunState() { return lldb::eStateStepping; } + + virtual llvm::Error GetStopDescription(lldb::StreamSP &stream) { + return llvm::Error::success(); + } +}; +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDTHREADPLANINTERFACE_H diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionArgParser.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionArgParser.h index 66b16112fce9..76a48fca6920 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionArgParser.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionArgParser.h @@ -29,6 +29,9 @@ struct OptionArgParser { static bool ToBoolean(llvm::StringRef s, bool fail_value, bool *success_ptr); + static llvm::Expected<bool> ToBoolean(llvm::StringRef option_name, + llvm::StringRef option_arg); + static char ToChar(llvm::StringRef s, char fail_value, bool *success_ptr); static int64_t ToOptionEnum(llvm::StringRef s, diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueSInt64.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueSInt64.h index 5efae627758a..3cf41d38c0ef 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueSInt64.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueSInt64.h @@ -86,8 +86,8 @@ public: protected: int64_t m_current_value = 0; int64_t m_default_value = 0; - int64_t m_min_value = INT64_MIN; - int64_t m_max_value = INT64_MAX; + int64_t m_min_value = std::numeric_limits<int64_t>::min(); + int64_t m_max_value = std::numeric_limits<int64_t>::max(); }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueUInt64.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueUInt64.h index 30c27bf73d99..07076075790c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueUInt64.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/OptionValueUInt64.h @@ -64,13 +64,35 @@ public: uint64_t GetDefaultValue() const { return m_default_value; } - void SetCurrentValue(uint64_t value) { m_current_value = value; } + bool SetCurrentValue(uint64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_current_value = value; + return true; + } + return false; + } + + bool SetDefaultValue(uint64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_default_value = value; + return true; + } + return false; + } + + void SetMinimumValue(int64_t v) { m_min_value = v; } + + uint64_t GetMinimumValue() const { return m_min_value; } + + void SetMaximumValue(int64_t v) { m_max_value = v; } - void SetDefaultValue(uint64_t value) { m_default_value = value; } + uint64_t GetMaximumValue() const { return m_max_value; } protected: uint64_t m_current_value = 0; uint64_t m_default_value = 0; + uint64_t m_min_value = std::numeric_limits<uint64_t>::min(); + uint64_t m_max_value = std::numeric_limits<uint64_t>::max(); }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/Options.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/Options.h index bf74927cf99d..9a6a17c2793f 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/Options.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/Options.h @@ -336,6 +336,41 @@ public: bool m_did_finalize = false; }; +/// Creates an error that represents the failure to parse an command line option +/// argument. This creates an error containing all information needed to show +/// the developer what went wrong when parsing their command. It is recommended +/// to use this instead of writing an error by hand. +/// +/// \param[in] option_arg +/// The argument that was attempted to be parsed. +/// +/// \param[in] short_option +/// The short form of the option. For example, if the flag is -f, the short +/// option is "f". +/// +/// \param[in] long_option +/// The long form of the option. This field is optional. If the flag is +/// --force, then the long option is "force". +/// +/// \param[in] additional_context +/// This is extra context that will get included in the error. This field is +/// optional. +/// +/// \return +/// An llvm::Error that contains a standardized format for what went wrong +/// when parsing and why. +llvm::Error CreateOptionParsingError(llvm::StringRef option_arg, + const char short_option, + llvm::StringRef long_option = {}, + llvm::StringRef additional_context = {}); + +static constexpr llvm::StringLiteral g_bool_parsing_error_message = + "Failed to parse as boolean"; +static constexpr llvm::StringLiteral g_int_parsing_error_message = + "Failed to parse as integer"; +static constexpr llvm::StringLiteral g_language_parsing_error_message = + "Unknown language"; + } // namespace lldb_private #endif // LLDB_INTERPRETER_OPTIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/contrib/llvm-project/lldb/include/lldb/Interpreter/ScriptInterpreter.h index b941f6012a11..05f0d7f0955f 100644 --- a/contrib/llvm-project/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/contrib/llvm-project/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -13,8 +13,10 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBData.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBEvent.h" #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBMemoryRegionInfo.h" +#include "lldb/API/SBStream.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/SearchFilter.h" @@ -250,50 +252,6 @@ public: return lldb::ValueObjectListSP(); } - virtual StructuredData::ObjectSP - CreateScriptedThreadPlan(const char *class_name, - const StructuredDataImpl &args_data, - std::string &error_str, - lldb::ThreadPlanSP thread_plan_sp) { - return StructuredData::ObjectSP(); - } - - virtual bool - ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, - Event *event, bool &script_error) { - script_error = true; - return true; - } - - virtual bool - ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, - Event *event, bool &script_error) { - script_error = true; - return true; - } - - virtual bool - ScriptedThreadPlanIsStale(StructuredData::ObjectSP implementor_sp, - bool &script_error) { - script_error = true; - return true; - } - - virtual lldb::StateType - ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, - bool &script_error) { - script_error = true; - return lldb::eStateStepping; - } - - virtual bool - ScriptedThreadPlanGetStopDescription(StructuredData::ObjectSP implementor_sp, - lldb_private::Stream *stream, - bool &script_error) { - script_error = true; - return false; - } - virtual StructuredData::GenericSP CreateScriptedBreakpointResolver(const char *class_name, const StructuredDataImpl &args_data, @@ -473,6 +431,20 @@ public: return false; } + virtual bool RunScriptBasedParsedCommand( + StructuredData::GenericSP impl_obj_sp, Args& args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Status &error, + const lldb_private::ExecutionContext &exe_ctx) { + return false; + } + + virtual std::optional<std::string> + GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp, + Args &args) { + return std::nullopt; + } + virtual bool RunScriptFormatKeyword(const char *impl_function, Process *process, std::string &output, Status &error) { @@ -517,6 +489,27 @@ public: dest.clear(); return false; } + + virtual StructuredData::ObjectSP + GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { + return {}; + } + + virtual StructuredData::ObjectSP + GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { + return {}; + } + + virtual bool SetOptionValueForCommandObject( + StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, + llvm::StringRef long_option, llvm::StringRef value) { + return false; + } + + virtual void OptionParsingStartedForCommandObject( + StructuredData::GenericSP cmd_obj_sp) { + return; + } virtual uint32_t GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) { @@ -563,6 +556,11 @@ public: return {}; } + virtual lldb::ScriptedThreadPlanInterfaceSP + CreateScriptedThreadPlanInterface() { + return {}; + } + virtual lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() { return {}; } @@ -581,6 +579,10 @@ public: Status GetStatusFromSBError(const lldb::SBError &error) const; + Event *GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const; + + lldb::StreamSP GetOpaqueTypeFromSBStream(const lldb::SBStream &stream) const; + lldb::BreakpointSP GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/Block.h b/contrib/llvm-project/lldb/include/lldb/Symbol/Block.h index 02fd2add5310..c9c4d5ad767d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/Block.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/Block.h @@ -355,6 +355,8 @@ public: // be able to get at any of the address ranges in a block. bool GetRangeAtIndex(uint32_t range_idx, AddressRange &range); + AddressRanges GetRanges(); + bool GetStartAddress(Address &addr); void SetDidParseVariables(bool b, bool set_children); diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerDecl.h b/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerDecl.h index 825a4f15836f..5c99cae3781c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerDecl.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerDecl.h @@ -73,6 +73,9 @@ public: CompilerDeclContext GetDeclContext() const; + // If this decl has a type, return it. + CompilerType GetType() const; + // If this decl represents a function, return the return type CompilerType GetFunctionReturnType() const; @@ -91,6 +94,10 @@ public: /// the subsequent entry, so the topmost entry is the global namespace. std::vector<lldb_private::CompilerContext> GetCompilerContext() const; + // If decl represents a constant value, return it. Otherwise, return an + // invalid/empty Scalar. + Scalar GetConstantValue() const; + private: TypeSystem *m_type_system = nullptr; void *m_opaque_decl = nullptr; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerType.h b/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerType.h index 414c44275aaa..70dacdcb7986 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerType.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/CompilerType.h @@ -262,6 +262,12 @@ public: size_t GetPointerByteSize() const; /// \} + unsigned GetPtrAuthKey() const; + + unsigned GetPtrAuthDiscriminator() const; + + bool GetPtrAuthAddressDiversity() const; + /// Accessors. /// \{ @@ -369,6 +375,12 @@ public: /// Create related types using the current type's AST CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) const; + + /// Return a new CompilerType adds a ptrauth modifier from the given 32-bit + /// opaque payload to this type if this type is valid and the type system + /// supports ptrauth modifiers, else return an invalid type. Note that this + /// does not check if this type is a pointer. + CompilerType AddPtrAuthModifier(uint32_t payload) const; /// \} /// Exploring the type. @@ -386,8 +398,9 @@ public: std::optional<size_t> GetTypeBitAlign(ExecutionContextScope *exe_scope) const; - uint32_t GetNumChildren(bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) const; + llvm::Expected<uint32_t> + GetNumChildren(bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) const; lldb::BasicType GetBasicTypeEnumeration() const; @@ -415,13 +428,15 @@ public: CompilerType GetVirtualBaseClassAtIndex(size_t idx, uint32_t *bit_offset_ptr) const; + CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const; + uint32_t GetIndexOfFieldWithName(const char *name, CompilerType *field_compiler_type = nullptr, uint64_t *bit_offset_ptr = nullptr, uint32_t *bitfield_bit_size_ptr = nullptr, bool *is_bitfield_ptr = nullptr) const; - CompilerType GetChildCompilerTypeAtIndex( + llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, uint32_t &child_byte_size, @@ -446,6 +461,8 @@ public: bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) const; + CompilerType GetDirectNestedTypeWithName(llvm::StringRef name) const; + /// Return the number of template arguments the type has. /// If expand_pack is true, then variadic argument packs are automatically /// expanded to their supplied arguments. If it is false an argument pack diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/LineEntry.h b/contrib/llvm-project/lldb/include/lldb/Symbol/LineEntry.h index c2daba916e3f..8da59cf0bd24 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/LineEntry.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/LineEntry.h @@ -130,31 +130,43 @@ struct LineEntry { /// Shared pointer to the target this LineEntry belongs to. void ApplyFileMappings(lldb::TargetSP target_sp); - // Member variables. - AddressRange range; ///< The section offset address range for this line entry. - FileSpec file; ///< The source file, possibly mapped by the target.source-map - ///setting - lldb::SupportFileSP - original_file_sp; ///< The original source file, from debug info. - uint32_t line = LLDB_INVALID_LINE_NUMBER; ///< The source line number, or zero - ///< if there is no line number - /// information. - uint16_t column = - 0; ///< The column number of the source line, or zero if there - /// is no column information. - uint16_t is_start_of_statement : 1, ///< Indicates this entry is the beginning - ///of a statement. - is_start_of_basic_block : 1, ///< Indicates this entry is the beginning of - ///a basic block. - is_prologue_end : 1, ///< Indicates this entry is one (of possibly many) - ///where execution should be suspended for an entry - ///breakpoint of a function. - is_epilogue_begin : 1, ///< Indicates this entry is one (of possibly many) - ///where execution should be suspended for an exit - ///breakpoint of a function. - is_terminal_entry : 1; ///< Indicates this entry is that of the first byte - ///after the end of a sequence of target machine - ///instructions. + /// Helper to access the file. + const FileSpec &GetFile() const { return file_sp->GetSpecOnly(); } + + /// The section offset address range for this line entry. + AddressRange range; + + /// The source file, possibly mapped by the target.source-map setting. + lldb::SupportFileSP file_sp; + + /// The original source file, from debug info. + lldb::SupportFileSP original_file_sp; + + /// The source line number, or LLDB_INVALID_LINE_NUMBER if there is no line + /// number information. + uint32_t line = LLDB_INVALID_LINE_NUMBER; + + /// The column number of the source line, or zero if there is no column + /// information. + uint16_t column = 0; + + /// Indicates this entry is the beginning of a statement. + uint16_t is_start_of_statement : 1; + + /// Indicates this entry is the beginning of a basic block. + uint16_t is_start_of_basic_block : 1; + + /// Indicates this entry is one (of possibly many) where execution should be + /// suspended for an entry breakpoint of a function. + uint16_t is_prologue_end : 1; + + /// Indicates this entry is one (of possibly many) where execution should be + /// suspended for an exit breakpoint of a function. + uint16_t is_epilogue_begin : 1; + + /// Indicates this entry is that of the first byte after the end of a sequence + /// of target machine instructions. + uint16_t is_terminal_entry : 1; }; /// Less than operator. diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/ObjectFile.h b/contrib/llvm-project/lldb/include/lldb/Symbol/ObjectFile.h index 6348d8103f85..8592323322e3 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/ObjectFile.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/ObjectFile.h @@ -178,6 +178,7 @@ public: lldb::offset_t file_offset, lldb::offset_t file_size, lldb_private::ModuleSpecList &specs); + static bool IsObjectFile(lldb_private::FileSpec file_spec); /// Split a path into a file path with object name. /// /// For paths like "/tmp/foo.a(bar.o)" we often need to split a path up into diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/SaveCoreOptions.h b/contrib/llvm-project/lldb/include/lldb/Symbol/SaveCoreOptions.h new file mode 100644 index 000000000000..583bc1f483d0 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/SaveCoreOptions.h @@ -0,0 +1,44 @@ +//===-- SaveCoreOptions.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_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H + +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +#include <optional> +#include <string> + +namespace lldb_private { + +class SaveCoreOptions { +public: + SaveCoreOptions(){}; + ~SaveCoreOptions() = default; + + lldb_private::Status SetPluginName(const char *name); + std::optional<std::string> GetPluginName() const; + + void SetStyle(lldb::SaveCoreStyle style); + lldb::SaveCoreStyle GetStyle() const; + + void SetOutputFile(lldb_private::FileSpec file); + const std::optional<lldb_private::FileSpec> GetOutputFile() const; + + void Clear(); + +private: + std::optional<std::string> m_plugin_name; + std::optional<lldb_private::FileSpec> m_file; + std::optional<lldb::SaveCoreStyle> m_style; +}; +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_SaveCoreOPTIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolContext.h b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolContext.h index bd33a71b46ca..0bc707070f85 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolContext.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolContext.h @@ -158,6 +158,7 @@ public: Stream *s, ExecutionContextScope *exe_scope, const Address &so_addr, bool show_fullpaths, bool show_module, bool show_inlined_frames, bool show_function_arguments, bool show_function_name, + bool show_function_display_name = false, std::optional<Stream::HighlightSettings> settings = std::nullopt) const; /// Get the address range contained within a symbol context. diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFile.h b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFile.h index f356f7b789fa..d20766788192 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFile.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFile.h @@ -381,7 +381,8 @@ public: /// Metrics gathering functions - /// Return the size in bytes of all debug information in the symbol file. + /// Return the size in bytes of all loaded debug information or total possible + /// debug info in the symbol file. /// /// If the debug information is contained in sections of an ObjectFile, then /// this call should add the size of all sections that contain debug @@ -391,7 +392,14 @@ public: /// entire file should be returned. The default implementation of this /// function will iterate over all sections in a module and add up their /// debug info only section byte sizes. - virtual uint64_t GetDebugInfoSize() = 0; + /// + /// \param load_all_debug_info + /// If true, force loading any symbol files if they are not yet loaded and + /// add to the total size. Default to false. + /// + /// \returns + /// Total currently loaded debug info size in bytes + virtual uint64_t GetDebugInfoSize(bool load_all_debug_info = false) = 0; /// Return the time taken to parse the debug information. /// @@ -534,7 +542,7 @@ public: void Dump(Stream &s) override; - uint64_t GetDebugInfoSize() override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; bool GetDebugInfoIndexWasLoadedFromCache() const override { return m_index_was_loaded_from_cache; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFileOnDemand.h b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFileOnDemand.h index 4e3009941aa7..8073d1816860 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFileOnDemand.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolFileOnDemand.h @@ -178,7 +178,7 @@ public: void PreloadSymbols() override; - uint64_t GetDebugInfoSize() override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; lldb_private::StatsDuration::Duration GetDebugInfoParseTime() override; lldb_private::StatsDuration::Duration GetDebugInfoIndexTime() override; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolLocation.h b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolLocation.h new file mode 100644 index 000000000000..be590c403b6e --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/SymbolLocation.h @@ -0,0 +1,32 @@ +//===-- SymbolLocation.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_SYMBOL_SYMBOLLOCATION_H +#define LLDB_SYMBOL_SYMBOLLOCATION_H + +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-private.h" + +#include <vector> + +namespace lldb_private { + +/// Stores a function module spec, symbol name and possibly an alternate symbol +/// name. +struct SymbolLocation { + FileSpec module_spec; + std::vector<ConstString> symbols; + + // The symbols are regular expressions. In such case all symbols are matched + // with their trailing @VER symbol version stripped. + bool symbols_are_regex = false; +}; + +} // namespace lldb_private +#endif // LLDB_SYMBOL_SYMBOLLOCATION_H diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/Type.h b/contrib/llvm-project/lldb/include/lldb/Symbol/Type.h index acd1a769f13c..c6f30cde8186 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/Type.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/Type.h @@ -21,6 +21,8 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLForwardCompat.h" +#include "llvm/Support/raw_ostream.h" #include <optional> #include <set> @@ -60,6 +62,8 @@ struct CompilerContext { CompilerContextKind kind; ConstString name; }; +llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const CompilerContext &rhs); /// Match \p context_chain against \p pattern, which may contain "Any" /// kinds. The \p context_chain should *not* contain any "Any" kinds. @@ -401,7 +405,9 @@ public: /// This type is the type whose UID is m_encoding_uid as an atomic type. eEncodingIsAtomicUID, /// This type is the synthetic type whose UID is m_encoding_uid. - eEncodingIsSyntheticUID + eEncodingIsSyntheticUID, + /// This type is a signed pointer. + eEncodingIsLLVMPtrAuthUID }; enum class ResolveState : unsigned char { @@ -440,7 +446,7 @@ public: std::optional<uint64_t> GetByteSize(ExecutionContextScope *exe_scope); - uint32_t GetNumChildren(bool omit_empty_base_classes); + llvm::Expected<uint32_t> GetNumChildren(bool omit_empty_base_classes); bool IsAggregateType(); @@ -490,12 +496,37 @@ public: static int Compare(const Type &a, const Type &b); + // Represents a parsed type name coming out of GetTypeScopeAndBasename. The + // structure holds StringRefs pointing to portions of the original name, and + // so must not be used after the name is destroyed. + struct ParsedName { + lldb::TypeClass type_class = lldb::eTypeClassAny; + + // Scopes of the type, starting with the outermost. Absolute type references + // have a "::" as the first scope. + llvm::SmallVector<llvm::StringRef> scope; + + llvm::StringRef basename; + + friend bool operator==(const ParsedName &lhs, const ParsedName &rhs) { + return lhs.type_class == rhs.type_class && lhs.scope == rhs.scope && + lhs.basename == rhs.basename; + } + + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, + const ParsedName &name) { + return os << llvm::formatv( + "Type::ParsedName({0:x}, [{1}], {2})", + llvm::to_underlying(name.type_class), + llvm::make_range(name.scope.begin(), name.scope.end()), + name.basename); + } + }; // From a fully qualified typename, split the type into the type basename and // the remaining type scope (namespaces/classes). - static bool GetTypeScopeAndBasename(llvm::StringRef name, - llvm::StringRef &scope, - llvm::StringRef &basename, - lldb::TypeClass &type_class); + static std::optional<ParsedName> + GetTypeScopeAndBasename(llvm::StringRef name); + void SetEncodingType(Type *encoding_type) { m_encoding_type = encoding_type; } uint32_t GetEncodingMask(); diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeList.h b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeList.h index 403469c989f5..d58772ad5b62 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeList.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeList.h @@ -49,15 +49,6 @@ public: void ForEach(std::function<bool(lldb::TypeSP &type_sp)> const &callback); - void RemoveMismatchedTypes(llvm::StringRef qualified_typename, - bool exact_match); - - void RemoveMismatchedTypes(llvm::StringRef type_scope, - llvm::StringRef type_basename, - lldb::TypeClass type_class, bool exact_match); - - void RemoveMismatchedTypes(lldb::TypeClass type_class); - private: typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeMap.h b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeMap.h index 433711875e55..89011efab5c3 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeMap.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeMap.h @@ -55,10 +55,6 @@ public: bool Remove(const lldb::TypeSP &type_sp); - void RemoveMismatchedTypes(llvm::StringRef type_scope, - llvm::StringRef type_basename, - lldb::TypeClass type_class, bool exact_match); - private: typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeSystem.h b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeSystem.h index 63829131556e..7d48f9b31613 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/TypeSystem.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/TypeSystem.h @@ -27,7 +27,10 @@ #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Type.h" +#include "lldb/Utility/Scalar.h" +#include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" +#include "lldb/lldb-types.h" class PDBASTParser; @@ -109,6 +112,8 @@ public: virtual std::vector<lldb_private::CompilerContext> DeclGetCompilerContext(void *opaque_decl); + virtual Scalar DeclGetConstantValue(void *opaque_decl) { return Scalar(); } + virtual CompilerType GetTypeForDecl(void *opaque_decl) = 0; // CompilerDeclContext functions @@ -204,6 +209,7 @@ public: // TypeSystems can support more than one language virtual bool SupportsLanguage(lldb::LanguageType language) = 0; + static bool SupportsLanguageStatic(lldb::LanguageType language); // Type Completion virtual bool GetCompleteType(lldb::opaque_compiler_type_t type) = 0; @@ -216,6 +222,14 @@ public: virtual uint32_t GetPointerByteSize() = 0; + virtual unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) = 0; + + virtual unsigned + GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) = 0; + + virtual bool + GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) = 0; + // Accessors virtual ConstString GetTypeName(lldb::opaque_compiler_type_t type, @@ -280,6 +294,9 @@ public: virtual CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type); + virtual CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload); + /// \param opaque_payload The m_payload field of Type, which may /// carry TypeSystem-specific extra information. virtual CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, @@ -300,9 +317,10 @@ public: virtual lldb::Format GetFormat(lldb::opaque_compiler_type_t type) = 0; - virtual uint32_t GetNumChildren(lldb::opaque_compiler_type_t type, - bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) = 0; + virtual llvm::Expected<uint32_t> + GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) = 0; virtual CompilerType GetBuiltinTypeByName(ConstString name); @@ -337,7 +355,12 @@ public: GetVirtualBaseClassAtIndex(lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) = 0; - virtual CompilerType GetChildCompilerTypeAtIndex( + virtual CompilerDecl GetStaticFieldWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) { + return CompilerDecl(); + } + + virtual llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, @@ -362,6 +385,12 @@ public: lldb::opaque_compiler_type_t type, llvm::StringRef name, bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) = 0; + virtual CompilerType + GetDirectNestedTypeWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) { + return CompilerType(); + } + virtual bool IsTemplateType(lldb::opaque_compiler_type_t type); virtual size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type, @@ -466,12 +495,10 @@ public: return IsPointerOrReferenceType(type, nullptr); } - virtual UserExpression * - GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, - Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) { + virtual UserExpression *GetUserExpression( + llvm::StringRef expr, llvm::StringRef prefix, SourceLanguage language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, ValueObject *ctx_obj) { return nullptr; } diff --git a/contrib/llvm-project/lldb/include/lldb/Symbol/UnwindTable.h b/contrib/llvm-project/lldb/include/lldb/Symbol/UnwindTable.h index f0ce7047de2d..26826e5d1b49 100644 --- a/contrib/llvm-project/lldb/include/lldb/Symbol/UnwindTable.h +++ b/contrib/llvm-project/lldb/include/lldb/Symbol/UnwindTable.h @@ -57,6 +57,10 @@ public: ArchSpec GetArchitecture(); + /// Called after a SymbolFile has been added to a Module to add any new + /// unwind sections that may now be available. + void Update(); + private: void Dump(Stream &s); diff --git a/contrib/llvm-project/lldb/include/lldb/Target/ABI.h b/contrib/llvm-project/lldb/include/lldb/Target/ABI.h index f600e29c7c4b..7b646d743346 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/ABI.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/ABI.h @@ -122,8 +122,8 @@ public: /// ARM uses bit zero to signify a code address is thumb, so any ARM ABI /// plug-ins would strip those bits. /// @{ - virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) { return pc; } - virtual lldb::addr_t FixDataAddress(lldb::addr_t pc) { return pc; } + virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc); + virtual lldb::addr_t FixDataAddress(lldb::addr_t pc); /// @} /// Use this method when you do not know, or do not care what kind of address @@ -166,10 +166,6 @@ protected: lldb::ProcessWP m_process_wp; std::unique_ptr<llvm::MCRegisterInfo> m_mc_register_info_up; - virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc, lldb::addr_t mask) { - return pc; - } - private: ABI(const ABI &) = delete; const ABI &operator=(const ABI &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/DynamicLoader.h b/contrib/llvm-project/lldb/include/lldb/Target/DynamicLoader.h index e508d192d275..0629e2faae7e 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/DynamicLoader.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/DynamicLoader.h @@ -9,6 +9,7 @@ #ifndef LLDB_TARGET_DYNAMICLOADER_H #define LLDB_TARGET_DYNAMICLOADER_H +#include "lldb/Core/Address.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" @@ -329,6 +330,13 @@ public: /// safe to call certain APIs or SPIs. virtual bool IsFullyInitialized() { return true; } + /// Return the `start` \b address in the dynamic loader module. + /// This is the address the process will begin executing with + /// `process launch --stop-at-entry`. + virtual std::optional<lldb_private::Address> GetStartAddress() { + return std::nullopt; + } + protected: // Utility methods for derived classes diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Language.h b/contrib/llvm-project/lldb/include/lldb/Target/Language.h index 0cbd8a32dccd..41d8eeef469e 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Language.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Language.h @@ -26,6 +26,15 @@ namespace lldb_private { +class LanguageProperties : public Properties { +public: + LanguageProperties(); + + static llvm::StringRef GetSettingName(); + + bool GetEnableFilterForLineBreakpoints() const; +}; + class Language : public PluginInterface { public: class TypeScavenger { @@ -272,6 +281,10 @@ public: return mangled.GetMangledName(); } + virtual ConstString GetDisplayDemangledName(Mangled mangled) const { + return mangled.GetDemangledName(); + } + virtual void GetExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s); @@ -324,6 +337,8 @@ public: static LanguageSet GetLanguagesSupportingTypeSystemsForExpressions(); static LanguageSet GetLanguagesSupportingREPLs(); + static LanguageProperties &GetGlobalLanguageProperties(); + // Given a mangled function name, calculates some alternative manglings since // the compiler mangling may not line up with the symbol we are expecting. virtual std::vector<ConstString> @@ -339,6 +354,31 @@ public: virtual llvm::StringRef GetInstanceVariableName() { return {}; } + /// Returns true if this SymbolContext should be ignored when setting + /// breakpoints by line (number or regex). Helpful for languages that create + /// artificial functions without meaningful user code associated with them + /// (e.g. code that gets expanded in late compilation stages, like by + /// CoroSplitter). + virtual bool IgnoreForLineBreakpoints(const SymbolContext &) const { + return false; + } + + /// Returns true if this Language supports exception breakpoints on throw via + /// a corresponding LanguageRuntime plugin. + virtual bool SupportsExceptionBreakpointsOnThrow() const { return false; } + + /// Returns true if this Language supports exception breakpoints on catch via + /// a corresponding LanguageRuntime plugin. + virtual bool SupportsExceptionBreakpointsOnCatch() const { return false; } + + /// Returns the keyword used for throw statements in this language, e.g. + /// Python uses \b raise. Defaults to \b throw. + virtual llvm::StringRef GetThrowKeyword() const { return "throw"; } + + /// Returns the keyword used for catch statements in this language, e.g. + /// Python uses \b except. Defaults to \b catch. + virtual llvm::StringRef GetCatchKeyword() const { return "catch"; } + protected: // Classes that inherit from Language can see and modify these diff --git a/contrib/llvm-project/lldb/include/lldb/Target/LanguageRuntime.h b/contrib/llvm-project/lldb/include/lldb/Target/LanguageRuntime.h index a2a9c0163f08..954d454c7858 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/LanguageRuntime.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/LanguageRuntime.h @@ -73,11 +73,12 @@ public: return nullptr; } - virtual bool GetObjectDescription(Stream &str, ValueObject &object) = 0; - - virtual bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) = 0; + virtual llvm::Error GetObjectDescription(Stream &str, + ValueObject &object) = 0; + virtual llvm::Error + GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) = 0; struct VTableInfo { Address addr; /// Address of the vtable's virtual function table @@ -169,9 +170,9 @@ public: return m_process->GetTarget().GetSearchFilterForModule(nullptr); } - virtual bool GetTypeBitSize(const CompilerType &compiler_type, - uint64_t &size) { - return false; + virtual std::optional<uint64_t> + GetTypeBitSize(const CompilerType &compiler_type) { + return {}; } virtual void SymbolsDidLoad(const ModuleList &module_list) {} diff --git a/contrib/llvm-project/lldb/include/lldb/Target/MemoryHistory.h b/contrib/llvm-project/lldb/include/lldb/Target/MemoryHistory.h index db1e86805996..cba5889afbf1 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/MemoryHistory.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/MemoryHistory.h @@ -1,5 +1,4 @@ -//===-- MemoryHistory.h ---------------------------------------------------*- -//C++ -*-===// +//===-- MemoryHistory.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. diff --git a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h index b082224c38ed..6bd4180fff70 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/MemoryTagManager.h @@ -103,7 +103,7 @@ public: // transport. virtual size_t GetTagSizeInBytes() const = 0; - // Unpack tags from their stored format (e.g. gdb qMemTags data) into seperate + // Unpack tags from their stored format (e.g. gdb qMemTags data) into separate // tags. // // Checks that each tag is within the expected value range and if granules is diff --git a/contrib/llvm-project/lldb/include/lldb/Target/PathMappingList.h b/contrib/llvm-project/lldb/include/lldb/Target/PathMappingList.h index 283452288734..1c0ff564739c 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/PathMappingList.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/PathMappingList.h @@ -11,6 +11,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" +#include "llvm/Support/Error.h" #include "llvm/Support/JSON.h" #include <map> #include <mutex> diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Platform.h b/contrib/llvm-project/lldb/include/lldb/Target/Platform.h index 13196ff74d66..5ed2fc33356d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Platform.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Platform.h @@ -29,6 +29,8 @@ #include "lldb/Utility/UserIDResolver.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" + +#include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" namespace lldb_private { @@ -106,21 +108,6 @@ public: static ArchSpec GetAugmentedArchSpec(Platform *platform, llvm::StringRef triple); - /// Find a platform plugin for a given process. - /// - /// Scans the installed Platform plug-ins and tries to find an instance that - /// can be used for \a process - /// - /// \param[in] process - /// The process for which to try and locate a platform - /// plug-in instance. - /// - /// \param[in] plugin_name - /// An optional name of a specific platform plug-in that - /// should be used. If nullptr, pick the best plug-in. - // static lldb::PlatformSP - // FindPlugin (Process *process, ConstString plugin_name); - /// Set the target's executable based off of the existing architecture /// information in \a target given a path to an executable \a exe_file. /// @@ -137,7 +124,7 @@ public: /// Returns \b true if this Platform plug-in was able to find /// a suitable executable, \b false otherwise. virtual Status ResolveExecutable(const ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, + lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr); /// Find a symbol file given a symbol file module specification. @@ -647,8 +634,8 @@ public: virtual std::string GetPlatformSpecificConnectionInformation() { return ""; } - virtual bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, - uint64_t &high); + virtual llvm::ErrorOr<llvm::MD5::MD5Result> + CalculateMD5(const FileSpec &file_spec); virtual uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { return 1; @@ -1002,11 +989,6 @@ protected: virtual const char *GetCacheHostname(); - virtual Status - ResolveRemoteExecutable(const ModuleSpec &module_spec, - lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr); - private: typedef std::function<Status(const ModuleSpec &)> ModuleResolver; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/PostMortemProcess.h b/contrib/llvm-project/lldb/include/lldb/Target/PostMortemProcess.h index 7207fc99ef29..9c9cd7fa599b 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/PostMortemProcess.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/PostMortemProcess.h @@ -24,7 +24,16 @@ class PostMortemProcess : public Process { using Process::Process; public: + PostMortemProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const FileSpec &core_file) + : Process(target_sp, listener_sp), m_core_file(core_file) {} + bool IsLiveDebugSession() const override { return false; } + + FileSpec GetCoreFile() const override { return m_core_file; } + +protected: + FileSpec m_core_file; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Process.h b/contrib/llvm-project/lldb/include/lldb/Target/Process.h index 24c599e044c7..c8475db8ae16 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Process.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Process.h @@ -43,6 +43,7 @@ #include "lldb/Target/ThreadList.h" #include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/Trace.h" +#include "lldb/Utility/AddressableBits.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Event.h" @@ -58,6 +59,7 @@ #include "llvm/ADT/AddressRanges.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Threading.h" #include "llvm/Support/VersionTuple.h" @@ -379,7 +381,7 @@ public: // These two functions fill out the Broadcaster interface: - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); static constexpr llvm::StringRef AttachSynchronousHijackListenerName = "lldb.internal.Process.AttachSynchronous.hijack"; @@ -388,7 +390,7 @@ public: static constexpr llvm::StringRef ResumeSynchronousHijackListenerName = "lldb.internal.Process.ResumeSynchronous.hijack"; - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } @@ -463,6 +465,8 @@ public: static bool SetUpdateStateOnRemoval(Event *event_ptr); private: + bool ForwardEventToPendingListeners(Event *event_ptr) override; + void SetUpdateStateOnRemoval() { m_update_state++; } void SetRestarted(bool new_value) { m_restarted = new_value; } @@ -913,8 +917,8 @@ public: /// \param[in] force_kill /// Whether lldb should force a kill (instead of a detach) from /// the inferior process. Normally if lldb launched a binary and - /// Destory is called, lldb kills it. If lldb attached to a - /// running process and Destory is called, lldb detaches. If + /// Destroy is called, lldb kills it. If lldb attached to a + /// running process and Destroy is called, lldb detaches. If /// this behavior needs to be over-ridden, this is the bool that /// can be used. /// @@ -1421,9 +1425,23 @@ public: virtual void DidExit() {} + /// Get the current address mask in the Process + /// + /// This mask can used to set/clear non-address bits in an addr_t. + /// + /// \return + /// The current address mask. + /// Bits which are set to 1 are not used for addressing. + /// An address mask of 0 means all bits are used for addressing. + /// An address mask of LLDB_INVALID_ADDRESS_MASK (all 1's) means + /// that no mask has been set. lldb::addr_t GetCodeAddressMask(); lldb::addr_t GetDataAddressMask(); + /// The highmem masks are for targets where we may have different masks + /// for low memory versus high memory addresses, and they will be left + /// as LLDB_INVALID_ADDRESS_MASK normally, meaning the base masks + /// should be applied to all addresses. lldb::addr_t GetHighmemCodeAddressMask(); lldb::addr_t GetHighmemDataAddressMask(); @@ -1502,6 +1520,13 @@ public: virtual bool IsLiveDebugSession() const { return true; }; + /// Provide a way to retrieve the core dump file that is loaded for debugging. + /// Only available if IsLiveDebugSession() returns true. + /// + /// \return + /// File path to the core file. + virtual FileSpec GetCoreFile() const { return {}; } + /// Before lldb detaches from a process, it warns the user that they are /// about to lose their debug session. In some cases, this warning doesn't /// need to be emitted -- for instance, with core file debugging where the @@ -2640,6 +2665,37 @@ void PruneThreadPlans(); return m_source_file_cache; } + /// Find a pattern within a memory region. + /// + /// This function searches for a pattern represented by the provided buffer + /// within the memory range specified by the low and high addresses. It uses + /// a bad character heuristic to optimize the search process. + /// + /// \param[in] low The starting address of the memory region to be searched. + /// (inclusive) + /// + /// \param[in] high The ending address of the memory region to be searched. + /// (exclusive) + /// + /// \param[in] buf A pointer to the buffer containing the pattern to be + /// searched. + /// + /// \param[in] buffer_size The size of the buffer in bytes. + /// + /// \return The address where the pattern was found or LLDB_INVALID_ADDRESS if + /// not found. + lldb::addr_t FindInMemory(lldb::addr_t low, lldb::addr_t high, + const uint8_t *buf, size_t size); + + AddressRanges FindRangesInMemory(const uint8_t *buf, uint64_t size, + const AddressRanges &ranges, + size_t alignment, size_t max_matches, + Status &error); + + lldb::addr_t FindInMemory(const uint8_t *buf, uint64_t size, + const AddressRange &range, size_t alignment, + Status &error); + protected: friend class Trace; @@ -2755,6 +2811,11 @@ protected: virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error) = 0; + virtual void DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr, + const uint8_t *buf, size_t size, + AddressRanges &matches, size_t alignment, + size_t max_matches); + /// DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has /// removed non address bits from load_addr. Override this method in /// subclasses of Process. @@ -3088,16 +3149,20 @@ protected: // if run while destructing. We use this flag to determine that. std::atomic<bool> m_destructing; - /// Mask for code an data addresses. The default value (0) means no mask is - /// set. The bits set to 1 indicate bits that are NOT significant for - /// addressing. - /// The highmem versions are for targets where we may have different masks - /// for low memory versus high memory addresses. + /// Mask for code an data addresses. + /// The default value LLDB_INVALID_ADDRESS_MASK means no mask has been set, + /// and addresses values should not be modified. + /// In these masks, the bits are set to 1 indicate bits that are not + /// significant for addressing. + /// The highmem masks are for targets where we may have different masks + /// for low memory versus high memory addresses, and they will be left + /// as LLDB_INVALID_ADDRESS_MASK normally, meaning the base masks + /// should be applied to all addresses. /// @{ - lldb::addr_t m_code_address_mask = 0; - lldb::addr_t m_data_address_mask = 0; - lldb::addr_t m_highmem_code_address_mask = 0; - lldb::addr_t m_highmem_data_address_mask = 0; + lldb::addr_t m_code_address_mask = LLDB_INVALID_ADDRESS_MASK; + lldb::addr_t m_data_address_mask = LLDB_INVALID_ADDRESS_MASK; + lldb::addr_t m_highmem_code_address_mask = LLDB_INVALID_ADDRESS_MASK; + lldb::addr_t m_highmem_data_address_mask = LLDB_INVALID_ADDRESS_MASK; /// @} bool m_clear_thread_plans_on_stop; @@ -3193,6 +3258,8 @@ protected: void LoadOperatingSystemPlugin(bool flush); + void SetAddressableBitMasks(AddressableBits bit_masks); + private: Status DestroyImpl(bool force_kill); @@ -3216,6 +3283,8 @@ private: Status LaunchPrivate(ProcessLaunchInfo &launch_info, lldb::StateType &state, lldb::EventSP &event_sp); + lldb::EventSP CreateEventFromProcessState(uint32_t event_type); + Process(const Process &) = delete; const Process &operator=(const Process &) = delete; }; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/ProcessTrace.h b/contrib/llvm-project/lldb/include/lldb/Target/ProcessTrace.h index 037dea232cc0..7a025100f680 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/ProcessTrace.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/ProcessTrace.h @@ -27,7 +27,8 @@ public: static llvm::StringRef GetPluginDescriptionStatic(); - ProcessTrace(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + ProcessTrace(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const FileSpec &core_file); ~ProcessTrace() override; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/RegisterFlags.h b/contrib/llvm-project/lldb/include/lldb/Target/RegisterFlags.h index 9b343e445678..1250fd033095 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/RegisterFlags.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/RegisterFlags.h @@ -13,11 +13,49 @@ #include <string> #include <vector> +#include "llvm/ADT/StringSet.h" + namespace lldb_private { -class StreamString; +class Stream; class Log; +class FieldEnum { +public: + struct Enumerator { + uint64_t m_value; + // Short name for the value. Shown in tables and when printing the field's + // value. For example "RZ". + std::string m_name; + + Enumerator(uint64_t value, std::string name) + : m_value(value), m_name(std::move(name)) {} + + void ToXML(Stream &strm) const; + + void DumpToLog(Log *log) const; + }; + + typedef std::vector<Enumerator> Enumerators; + + // GDB also includes a "size" that is the size of the underlying register. + // We will not store that here but instead use the size of the register + // this gets attached to when emitting XML. + FieldEnum(std::string id, const Enumerators &enumerators); + + const Enumerators &GetEnumerators() const { return m_enumerators; } + + const std::string &GetID() const { return m_id; } + + void ToXML(Stream &strm, unsigned size) const; + + void DumpToLog(Log *log) const; + +private: + std::string m_id; + Enumerators m_enumerators; +}; + class RegisterFlags { public: class Field { @@ -26,17 +64,27 @@ public: /// significant bit. The start bit must be <= the end bit. Field(std::string name, unsigned start, unsigned end); + /// Construct a field that also has some known enum values. + Field(std::string name, unsigned start, unsigned end, + const FieldEnum *enum_type); + /// Construct a field that occupies a single bit. - Field(std::string name, unsigned bit_position) - : m_name(std::move(name)), m_start(bit_position), m_end(bit_position) {} + Field(std::string name, unsigned bit_position); /// Get size of the field in bits. Will always be at least 1. - unsigned GetSizeInBits() const { return m_end - m_start + 1; } + unsigned GetSizeInBits() const; + + /// Identical to GetSizeInBits, but for the GDB client to use. + static unsigned GetSizeInBits(unsigned start, unsigned end); /// A mask that covers all bits of the field. - uint64_t GetMask() const { - return (((uint64_t)1 << (GetSizeInBits())) - 1) << m_start; - } + uint64_t GetMask() const; + + /// The maximum unsigned value that could be contained in this field. + uint64_t GetMaxValue() const; + + /// Identical to GetMaxValue but for the GDB client to use. + static uint64_t GetMaxValue(unsigned start, unsigned end); /// Extract value of the field from a whole register value. uint64_t GetValue(uint64_t register_value) const { @@ -46,8 +94,9 @@ public: const std::string &GetName() const { return m_name; } unsigned GetStart() const { return m_start; } unsigned GetEnd() const { return m_end; } + const FieldEnum *GetEnum() const { return m_enum_type; } bool Overlaps(const Field &other) const; - void log(Log *log) const; + void DumpToLog(Log *log) const; /// Return the number of bits between this field and the other, that are not /// covered by either field. @@ -56,7 +105,7 @@ public: /// Output XML that describes this field, to be inserted into a target XML /// file. Reserved characters in field names like "<" are replaced with /// their XML safe equivalents like ">". - void ToXML(StreamString &strm) const; + void ToXML(Stream &strm) const; bool operator<(const Field &rhs) const { return GetStart() < rhs.GetStart(); @@ -69,12 +118,15 @@ public: private: std::string m_name; + /// Start/end bit positions. Where start N, end N means a single bit /// field at position N. We expect that start <= end. Bit positions begin /// at 0. /// Start is the LSB, end is the MSB. unsigned m_start; unsigned m_end; + + const FieldEnum *m_enum_type; }; /// This assumes that: @@ -89,6 +141,10 @@ public: /// when runtime field detection is needed. void SetFields(const std::vector<Field> &fields); + /// Make a string where each line contains the name of a field that has + /// enum values, and lists what those values are. + std::string DumpEnums(uint32_t max_width) const; + // Reverse the order of the fields, keeping their values the same. // For example a field from bit 31 to 30 with value 0b10 will become bits // 1 to 0, with the same 0b10 value. @@ -109,7 +165,7 @@ public: const std::vector<Field> &GetFields() const { return m_fields; } const std::string &GetID() const { return m_id; } unsigned GetSize() const { return m_size; } - void log(Log *log) const; + void DumpToLog(Log *log) const; /// Produce a text table showing the layout of all the fields. Unnamed/padding /// fields will be included, with only their positions shown. @@ -118,8 +174,17 @@ public: /// be split into many tables as needed. std::string AsTable(uint32_t max_width) const; - // Output XML that describes this set of flags. - void ToXML(StreamString &strm) const; + /// Output XML that describes this set of flags. + /// EnumsToXML should have been called before this. + void ToXML(Stream &strm) const; + + /// Enum types must be defined before use, and + /// GDBRemoteCommunicationServerLLGS view of the register types is based only + /// on the registers. So this method emits any enum types that the upcoming + /// set of fields may need. "seen" is a set of Enum IDs that we have already + /// printed, that is updated with any printed by this call. This prevents us + /// printing the same enum multiple times. + void EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const; private: const std::string m_id; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/RemoteAwarePlatform.h b/contrib/llvm-project/lldb/include/lldb/Target/RemoteAwarePlatform.h index d183815e1c8b..fb2eecfaa23a 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/RemoteAwarePlatform.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/RemoteAwarePlatform.h @@ -20,13 +20,14 @@ class RemoteAwarePlatform : public Platform { public: using Platform::Platform; + virtual Status + ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) override; + bool GetModuleSpec(const FileSpec &module_file_spec, const ArchSpec &arch, ModuleSpec &module_spec) override; - Status - ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr) override; - lldb::user_id_t OpenFile(const FileSpec &file_spec, File::OpenOptions flags, uint32_t mode, Status &error) override; @@ -58,8 +59,8 @@ public: Status SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) override; - bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, - uint64_t &high) override; + llvm::ErrorOr<llvm::MD5::MD5Result> + CalculateMD5(const FileSpec &file_spec) override; Status GetFileWithUUID(const FileSpec &platform_file, const UUID *uuid, FileSpec &local_file) override; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/StackFrame.h b/contrib/llvm-project/lldb/include/lldb/Target/StackFrame.h index 6c18511c6e1a..52f0a1ee6621 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/StackFrame.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/StackFrame.h @@ -1,3 +1,4 @@ + //===-- StackFrame.h --------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. @@ -446,13 +447,12 @@ public: /// Query this frame to determine what the default language should be when /// parsing expressions given the execution context. /// - /// \return - /// The language of the frame if known, else lldb::eLanguageTypeUnknown. - lldb::LanguageType GetLanguage(); + /// \return The language of the frame if known. + SourceLanguage GetLanguage(); - // similar to GetLanguage(), but is allowed to take a potentially incorrect - // guess if exact information is not available - lldb::LanguageType GuessLanguage(); + /// Similar to GetLanguage(), but is allowed to take a potentially incorrect + /// guess if exact information is not available. + SourceLanguage GuessLanguage(); /// Attempt to econstruct the ValueObject for a given raw address touched by /// the current instruction. The ExpressionPath should indicate how to get diff --git a/contrib/llvm-project/lldb/include/lldb/Target/StackFrameRecognizer.h b/contrib/llvm-project/lldb/include/lldb/Target/StackFrameRecognizer.h index 419f0c0aac1f..e9ac2750192e 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -17,6 +17,7 @@ #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" +#include <deque> #include <optional> #include <vector> @@ -164,7 +165,8 @@ class ValueObjectRecognizerSynthesizedValue : public ValueObject { m_value = m_parent->GetValue(); return true; } - size_t CalculateNumChildren(uint32_t max = UINT32_MAX) override { + llvm::Expected<uint32_t> + CalculateNumChildren(uint32_t max = UINT32_MAX) override { return m_parent->GetNumChildren(max); } CompilerType GetCompilerTypeImpl() override { diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Statistics.h b/contrib/llvm-project/lldb/include/lldb/Target/Statistics.h index f672786f58f8..35bd7f8a66e0 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Statistics.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Statistics.h @@ -130,10 +130,55 @@ struct ConstStringStats { ConstString::MemoryStats stats = ConstString::GetMemoryStats(); }; +struct StatisticsOptions { +public: + void SetSummaryOnly(bool value) { m_summary_only = value; } + bool GetSummaryOnly() const { return m_summary_only.value_or(false); } + + void SetLoadAllDebugInfo(bool value) { m_load_all_debug_info = value; } + bool GetLoadAllDebugInfo() const { + return m_load_all_debug_info.value_or(false); + } + + void SetIncludeTargets(bool value) { m_include_targets = value; } + bool GetIncludeTargets() const { + if (m_include_targets.has_value()) + return m_include_targets.value(); + // Default to true in both default mode and summary mode. + return true; + } + + void SetIncludeModules(bool value) { m_include_modules = value; } + bool GetIncludeModules() const { + if (m_include_modules.has_value()) + return m_include_modules.value(); + // `m_include_modules` has no value set, so return a value based on + // `m_summary_only`. + return !GetSummaryOnly(); + } + + void SetIncludeTranscript(bool value) { m_include_transcript = value; } + bool GetIncludeTranscript() const { + if (m_include_transcript.has_value()) + return m_include_transcript.value(); + // `m_include_transcript` has no value set, so return a value based on + // `m_summary_only`. + return !GetSummaryOnly(); + } + +private: + std::optional<bool> m_summary_only; + std::optional<bool> m_load_all_debug_info; + std::optional<bool> m_include_targets; + std::optional<bool> m_include_modules; + std::optional<bool> m_include_transcript; +}; + /// A class that represents statistics for a since lldb_private::Target. class TargetStats { public: - llvm::json::Value ToJSON(Target &target); + llvm::json::Value ToJSON(Target &target, + const lldb_private::StatisticsOptions &options); void SetLaunchOrAttachTime(); void SetFirstPrivateStopTime(); @@ -171,9 +216,15 @@ public: /// The single target to emit statistics for if non NULL, otherwise dump /// statistics only for the specified target. /// + /// \param summary_only + /// If true, only report high level summary statistics without + /// targets/modules/breakpoints etc.. details. + /// /// \return /// Returns a JSON value that contains all target metrics. - static llvm::json::Value ReportStatistics(Debugger &debugger, Target *target); + static llvm::json::Value + ReportStatistics(Debugger &debugger, Target *target, + const lldb_private::StatisticsOptions &options); protected: // Collecting stats can be set to true to collect stats that are expensive diff --git a/contrib/llvm-project/lldb/include/lldb/Target/StopInfo.h b/contrib/llvm-project/lldb/include/lldb/Target/StopInfo.h index 305fc5d0e0fb..d1848fcbbbdb 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/StopInfo.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/StopInfo.h @@ -79,6 +79,11 @@ public: virtual bool IsValidForOperatingSystemThread(Thread &thread) { return true; } + /// A Continue operation can result in a false stop event + /// before any execution has happened. We need to detect this + /// and silently continue again one more time. + virtual bool WasContinueInterrupted(Thread &thread) { return false; } + // Sometimes the thread plan logic will know that it wants a given stop to // stop or not, regardless of what the ordinary logic for that StopInfo would // dictate. The main example of this is the ThreadPlanCallFunction, which diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Target.h b/contrib/llvm-project/lldb/include/lldb/Target/Target.h index c37682e2a038..5d5ae1bfcd3b 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Target.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Target.h @@ -200,7 +200,7 @@ public: bool GetBreakpointsConsultPlatformAvoidList(); - lldb::LanguageType GetLanguage() const; + SourceLanguage GetLanguage() const; llvm::StringRef GetExpressionPrefixContents(); @@ -244,8 +244,6 @@ public: bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const; - void SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b); - void SetRequireHardwareBreakpoints(bool b); bool GetRequireHardwareBreakpoints() const; @@ -259,6 +257,10 @@ public: bool GetDebugUtilityExpression() const; private: + std::optional<bool> + GetExperimentalPropertyValue(size_t prop_idx, + ExecutionContext *exe_ctx = nullptr) const; + // Callbacks for m_launch_info. void Arg0ValueChangedCallback(); void RunArgsValueChangedCallback(); @@ -308,9 +310,18 @@ public: m_execution_policy = policy; } - lldb::LanguageType GetLanguage() const { return m_language; } + SourceLanguage GetLanguage() const { return m_language; } + + void SetLanguage(lldb::LanguageType language_type) { + m_language = SourceLanguage(language_type); + } - void SetLanguage(lldb::LanguageType language) { m_language = language; } + /// Set the language using a pair of language code and version as + /// defined by the DWARF 6 specification. + /// WARNING: These codes may change until DWARF 6 is finalized. + void SetLanguage(uint16_t name, uint32_t version) { + m_language = SourceLanguage(name, version); + } bool DoesCoerceToId() const { return m_coerce_to_id; } @@ -443,7 +454,7 @@ public: private: ExecutionPolicy m_execution_policy = default_execution_policy; - lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; + SourceLanguage m_language; std::string m_prefix; bool m_coerce_to_id = false; bool m_unwind_on_error = true; @@ -497,9 +508,9 @@ public: // These two functions fill out the Broadcaster interface: - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } @@ -1066,9 +1077,11 @@ public: // section, then read from the file cache // 2 - if there is a process, then read from memory // 3 - if there is no process, then read from the file cache - size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, - Status &error, bool force_live_memory = false, - lldb::addr_t *load_addr_ptr = nullptr); + // + // The method is virtual for mocking in the unit tests. + virtual size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, + Status &error, bool force_live_memory = false, + lldb::addr_t *load_addr_ptr = nullptr); size_t ReadCStringFromMemory(const Address &addr, std::string &out_str, Status &error, bool force_live_memory = false); @@ -1158,7 +1171,7 @@ public: UserExpression * GetUserExpressionForLanguage(llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, + SourceLanguage language, Expression::ResultType desired_type, const EvaluateExpressionOptions &options, ValueObject *ctx_obj, Status &error); @@ -1599,11 +1612,12 @@ public: /// /// \return /// Returns a JSON value that contains all target metrics. - llvm::json::Value ReportStatistics(); + llvm::json::Value + ReportStatistics(const lldb_private::StatisticsOptions &options); TargetStats &GetStatistics() { return m_stats; } -private: +protected: /// Construct with optional file and arch. /// /// This member is private. Clients must use diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TargetList.h b/contrib/llvm-project/lldb/include/lldb/Target/TargetList.h index a0bc6f1f820b..a0cddc6b2966 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/TargetList.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/TargetList.h @@ -37,9 +37,9 @@ public: // These two functions fill out the Broadcaster interface: - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } diff --git a/contrib/llvm-project/lldb/include/lldb/Target/Thread.h b/contrib/llvm-project/lldb/include/lldb/Target/Thread.h index e423dd4a6d2b..2ff1f50d497e 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/Thread.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/Thread.h @@ -11,6 +11,7 @@ #include <memory> #include <mutex> +#include <optional> #include <string> #include <vector> @@ -25,6 +26,7 @@ #include "lldb/Utility/UnimplementedError.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" +#include "llvm/Support/MemoryBuffer.h" #define LLDB_THREAD_MAX_STOP_EXC_DATA 8 @@ -73,9 +75,9 @@ public: eBroadcastBitThreadSelected = (1 << 4) }; - static ConstString &GetStaticBroadcasterClass(); + static llvm::StringRef GetStaticBroadcasterClass(); - ConstString &GetBroadcasterClass() const override { + llvm::StringRef GetBroadcasterClass() const override { return GetStaticBroadcasterClass(); } @@ -390,6 +392,13 @@ public: /// and having the thread call the SystemRuntime again. virtual bool ThreadHasQueueInformation() const { return false; } + /// GetStackFrameCount can be expensive. Stacks can get very deep, and they + /// require memory reads for each frame. So only use GetStackFrameCount when + /// you need to know the depth of the stack. When iterating over frames, its + /// better to generate the frames one by one with GetFrameAtIndex, and when + /// that returns NULL, you are at the end of the stack. That way your loop + /// will only do the work it needs to, without forcing lldb to realize + /// StackFrames you weren't going to look at. virtual uint32_t GetStackFrameCount() { return GetStackFrameList()->GetNumFrames(); } @@ -1155,13 +1164,20 @@ public: void CalculatePublicStopInfo(); - // Ask the thread subclass to set its stop info. - // - // Thread subclasses should call Thread::SetStopInfo(...) with the reason the - // thread stopped. - // - // \return - // True if Thread::SetStopInfo(...) was called, false otherwise. + /// Ask the thread subclass to set its stop info. + /// + /// Thread subclasses should call Thread::SetStopInfo(...) with the reason the + /// thread stopped. + /// + /// A thread that is sitting at a breakpoint site, but has not yet executed + /// the breakpoint instruction, should have a breakpoint-hit StopInfo set. + /// When execution is resumed, any thread sitting at a breakpoint site will + /// instruction-step over the breakpoint instruction silently, and we will + /// never record this breakpoint as being hit, updating the hit count, + /// possibly executing breakpoint commands or conditions. + /// + /// \return + /// True if Thread::SetStopInfo(...) was called, false otherwise. virtual bool CalculateStopInfo() = 0; // Gets the temporary resume state for a thread. @@ -1219,6 +1235,16 @@ public: lldb::ValueObjectSP GetSiginfoValue(); + /// Request the pc value the thread had when previously stopped. + /// + /// When the thread performs execution, it copies the current RegisterContext + /// GetPC() value. This method returns that value, if it is available. + /// + /// \return + /// The PC value before execution was resumed. May not be available; + /// an empty std::optional is returned in that case. + std::optional<lldb::addr_t> GetPreviousFrameZeroPC(); + protected: friend class ThreadPlan; friend class ThreadList; @@ -1299,6 +1325,9 @@ protected: ///populated after a thread stops. lldb::StackFrameListSP m_prev_frames_sp; ///< The previous stack frames from ///the last time this thread stopped. + std::optional<lldb::addr_t> + m_prev_framezero_pc; ///< Frame 0's PC the last + /// time this thread was stopped. int m_resume_signal; ///< The signal that should be used when continuing this ///thread. lldb::StateType m_resume_state; ///< This state is used to force a thread to diff --git a/contrib/llvm-project/lldb/include/lldb/Target/ThreadList.h b/contrib/llvm-project/lldb/include/lldb/Target/ThreadList.h index 6af04f8ffc37..f931bb83a8ce 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/ThreadList.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/ThreadList.h @@ -27,12 +27,13 @@ class ThreadList : public ThreadCollection { friend class Process; public: - ThreadList(Process *process); + ThreadList(Process &process); ThreadList(const ThreadList &rhs); ~ThreadList() override; + /// Precondition: both thread lists must be belong to the same process. const ThreadList &operator=(const ThreadList &rhs); uint32_t GetSize(bool can_update = true); @@ -135,6 +136,7 @@ public: std::recursive_mutex &GetMutex() const override; + /// Precondition: both thread lists must be belong to the same process. void Update(ThreadList &rhs); protected: @@ -143,7 +145,7 @@ protected: void NotifySelectedThreadChanged(lldb::tid_t tid); // Classes that inherit from Process can see and modify these - Process *m_process; ///< The process that manages this thread list. + Process &m_process; ///< The process that manages this thread list. uint32_t m_stop_id; ///< The process stop ID that this thread list is valid for. lldb::tid_t diff --git a/contrib/llvm-project/lldb/include/lldb/Target/ThreadPlanPython.h b/contrib/llvm-project/lldb/include/lldb/Target/ThreadPlanPython.h index 64854d66b8f2..da106faf951d 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/ThreadPlanPython.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/ThreadPlanPython.h @@ -13,6 +13,7 @@ #include <string> #include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" @@ -70,6 +71,7 @@ private: StreamString m_stop_description; // Cache the stop description here bool m_did_push; bool m_stop_others; + lldb::ScriptedThreadPlanInterfaceSP m_interface; ThreadPlanPython(const ThreadPlanPython &) = delete; const ThreadPlanPython &operator=(const ThreadPlanPython &) = delete; diff --git a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h index ca08dc254182..d3cea4b28449 100644 --- a/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h +++ b/contrib/llvm-project/lldb/include/lldb/Target/TraceDumper.h @@ -9,6 +9,7 @@ #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/TraceCursor.h" #include <optional> +#include <stack> #ifndef LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H #define LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H diff --git a/contrib/llvm-project/lldb/include/lldb/Target/VerboseTrapFrameRecognizer.h b/contrib/llvm-project/lldb/include/lldb/Target/VerboseTrapFrameRecognizer.h new file mode 100644 index 000000000000..7e045760a28b --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Target/VerboseTrapFrameRecognizer.h @@ -0,0 +1,39 @@ +#ifndef LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H +#define LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H + +#include "lldb/Target/StackFrameRecognizer.h" + +namespace lldb_private { + +void RegisterVerboseTrapFrameRecognizer(Process &process); + +/// Holds the stack frame that caused the Verbose trap and the inlined stop +/// reason message. +class VerboseTrapRecognizedStackFrame : public RecognizedStackFrame { +public: + VerboseTrapRecognizedStackFrame(lldb::StackFrameSP most_relevant_frame_sp, + std::string stop_desc); + + lldb::StackFrameSP GetMostRelevantFrame() override; + +private: + lldb::StackFrameSP m_most_relevant_frame; +}; + +/// When a thread stops, it checks the current frame contains a +/// Verbose Trap diagnostic. If so, it returns a \a +/// VerboseTrapRecognizedStackFrame holding the diagnostic a stop reason +/// description with and the parent frame as the most relavant frame. +class VerboseTrapFrameRecognizer : public StackFrameRecognizer { +public: + std::string GetName() override { + return "Verbose Trap StackFrame Recognizer"; + } + + lldb::RecognizedStackFrameSP + RecognizeFrame(lldb::StackFrameSP frame) override; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_VERBOSETRAPFRAMERECOGNIZER_H diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/AddressableBits.h b/contrib/llvm-project/lldb/include/lldb/Utility/AddressableBits.h index 13c21329a8c6..0d27c3561ec2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/AddressableBits.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/AddressableBits.h @@ -10,6 +10,7 @@ #define LLDB_UTILITY_ADDRESSABLEBITS_H #include "lldb/lldb-forward.h" +#include "lldb/lldb-public.h" namespace lldb_private { @@ -31,9 +32,13 @@ public: void SetLowmemAddressableBits(uint32_t lowmem_addressing_bits); + uint32_t GetLowmemAddressableBits() const; + void SetHighmemAddressableBits(uint32_t highmem_addressing_bits); - void SetProcessMasks(lldb_private::Process &process); + uint32_t GetHighmemAddressableBits() const; + + static lldb::addr_t AddressableBitToMask(uint32_t addressable_bits); private: uint32_t m_low_memory_addr_bits; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/ArchSpec.h b/contrib/llvm-project/lldb/include/lldb/Utility/ArchSpec.h index a226a3a5a9b7..50830b889b91 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/ArchSpec.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/ArchSpec.h @@ -505,11 +505,6 @@ public: bool IsFullySpecifiedTriple() const; - void PiecewiseTripleCompare(const ArchSpec &other, bool &arch_different, - bool &vendor_different, bool &os_different, - bool &os_version_different, - bool &env_different) const; - /// Detect whether this architecture uses thumb code exclusively /// /// Some embedded ARM chips (e.g. the ARM Cortex M0-7 line) can only execute diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Args.h b/contrib/llvm-project/lldb/include/lldb/Utility/Args.h index 40b9358484b6..757f7e2ba5ec 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Args.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Args.h @@ -13,8 +13,8 @@ #include "lldb/lldb-private-types.h" #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/YAMLTraits.h" #include <string> #include <utility> #include <vector> diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Broadcaster.h b/contrib/llvm-project/lldb/include/lldb/Utility/Broadcaster.h index c8127f0a921d..c6f63f191657 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Broadcaster.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Broadcaster.h @@ -39,12 +39,12 @@ namespace lldb_private { /// Debugger maintains a list of BroadcastEventSpec's and when it is made class BroadcastEventSpec { public: - BroadcastEventSpec(const ConstString &broadcaster_class, uint32_t event_bits) + BroadcastEventSpec(llvm::StringRef broadcaster_class, uint32_t event_bits) : m_broadcaster_class(broadcaster_class), m_event_bits(event_bits) {} ~BroadcastEventSpec() = default; - ConstString GetBroadcasterClass() const { return m_broadcaster_class; } + const std::string &GetBroadcasterClass() const { return m_broadcaster_class; } uint32_t GetEventBits() const { return m_event_bits; } @@ -67,7 +67,7 @@ public: bool operator<(const BroadcastEventSpec &rhs) const; private: - ConstString m_broadcaster_class; + std::string m_broadcaster_class; uint32_t m_event_bits; }; @@ -87,12 +87,6 @@ public: ~BroadcasterManager() = default; - uint32_t RegisterListenerForEvents(const lldb::ListenerSP &listener_sp, - const BroadcastEventSpec &event_spec); - - bool UnregisterListenerForEvents(const lldb::ListenerSP &listener_sp, - const BroadcastEventSpec &event_spec); - lldb::ListenerSP GetListenerForEventSpec(const BroadcastEventSpec &event_spec) const; @@ -105,13 +99,20 @@ public: void Clear(); private: + uint32_t + RegisterListenerForEventsNoLock(const lldb::ListenerSP &listener_sp, + const BroadcastEventSpec &event_spec); + + bool UnregisterListenerForEventsNoLock(const lldb::ListenerSP &listener_sp, + const BroadcastEventSpec &event_spec); + typedef std::pair<BroadcastEventSpec, lldb::ListenerSP> event_listener_key; typedef std::map<BroadcastEventSpec, lldb::ListenerSP> collection; typedef std::set<lldb::ListenerSP> listener_collection; collection m_event_map; listener_collection m_listeners; - mutable std::recursive_mutex m_manager_mutex; + mutable std::mutex m_manager_mutex; }; /// \class Broadcaster Broadcaster.h "lldb/Utility/Broadcaster.h" An event @@ -181,9 +182,8 @@ public: m_broadcaster_sp->BroadcastEvent(event_type); } - void BroadcastEventIfUnique(uint32_t event_type, - EventData *event_data = nullptr) { - m_broadcaster_sp->BroadcastEventIfUnique(event_type, event_data); + void BroadcastEventIfUnique(uint32_t event_type) { + m_broadcaster_sp->BroadcastEventIfUnique(event_type); } void Clear() { m_broadcaster_sp->Clear(); } @@ -308,7 +308,7 @@ public: /// FIXME: Probably should make a ManagedBroadcaster subclass with all the /// bits needed to work with the BroadcasterManager, so that it is clearer /// how to add one. - virtual ConstString &GetBroadcasterClass() const; + virtual llvm::StringRef GetBroadcasterClass() const; lldb::BroadcasterManagerSP GetManager(); @@ -351,8 +351,7 @@ protected: void BroadcastEvent(uint32_t event_type, const lldb::EventDataSP &event_data_sp); - void BroadcastEventIfUnique(uint32_t event_type, - EventData *event_data = nullptr); + void BroadcastEventIfUnique(uint32_t event_type); void Clear(); @@ -443,7 +442,7 @@ protected: collection m_listeners; /// A mutex that protects \a m_listeners. - std::recursive_mutex m_listeners_mutex; + std::mutex m_listeners_mutex; /// See the discussion of Broadcasters and Listeners above. lldb::ListenerSP m_primary_listener_sp; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/ConstString.h b/contrib/llvm-project/lldb/include/lldb/Utility/ConstString.h index cbea4cbf916a..692ecb63bd76 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/ConstString.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/ConstString.h @@ -167,8 +167,14 @@ public: // Implicitly convert \class ConstString instances to \class StringRef. operator llvm::StringRef() const { return GetStringRef(); } - // Implicitly convert \class ConstString instances to \calss std::string_view. - operator std::string_view() const { return std::string_view(m_string, GetLength()); } + + // Explicitly convert \class ConstString instances to \class std::string_view. + explicit operator std::string_view() const { + return std::string_view(m_string, GetLength()); + } + + // Explicitly convert \class ConstString instances to \class std::string. + explicit operator std::string() const { return GetString(); } /// Get the string value as a C string. /// @@ -192,6 +198,11 @@ public: return llvm::StringRef(m_string, GetLength()); } + /// Get the string value as a std::string + std::string GetString() const { + return std::string(AsCString(""), GetLength()); + } + /// Get the string value as a C string. /// /// Get the value of the contained string as a NULL terminated C string diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/ErrorMessages.h b/contrib/llvm-project/lldb/include/lldb/Utility/ErrorMessages.h new file mode 100644 index 000000000000..116e29e0e618 --- /dev/null +++ b/contrib/llvm-project/lldb/include/lldb/Utility/ErrorMessages.h @@ -0,0 +1,22 @@ +//===-- ErrorMessages.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_UTILITY_ERROR_MESSAGES_H +#define LLDB_UTILITY_ERROR_MESSAGES_H + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" +#include <string> + +namespace lldb_private { + +/// Produce a human-readable rendition of an ExpressionResults value. +std::string toString(lldb::ExpressionResults e); + +} // namespace lldb_private +#endif diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Event.h b/contrib/llvm-project/lldb/include/lldb/Utility/Event.h index 3de0401191ca..4f58f257d4a2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Event.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Event.h @@ -48,6 +48,17 @@ public: virtual void Dump(Stream *s) const; private: + /// This will be queried for a Broadcaster with a primary and some secondary + /// listeners after the primary listener pulled the event from the event queue + /// and ran its DoOnRemoval, right before the event is delivered. + /// If it returns true, the event will also be forwarded to the secondary + /// listeners, and if false, event propagation stops at the primary listener. + /// Some broadcasters (particularly the Process broadcaster) fetch events on + /// a private Listener, and then forward the event to the Public Listeners + /// after some processing. The Process broadcaster does not want to forward + /// to the secondary listeners at the private processing stage. + virtual bool ForwardEventToPendingListeners(Event *event_ptr) { return true; } + virtual void DoOnRemoval(Event *event_ptr) {} EventData(const EventData &) = delete; @@ -60,12 +71,8 @@ public: // Constructors EventDataBytes(); - EventDataBytes(const char *cstr); - EventDataBytes(llvm::StringRef str); - EventDataBytes(const void *src, size_t src_len); - ~EventDataBytes() override; // Member functions @@ -77,12 +84,6 @@ public: size_t GetByteSize() const; - void SetBytes(const void *src, size_t src_len); - - void SwapBytes(std::string &new_bytes); - - void SetBytesFromCString(const char *cstr); - // Static functions static const EventDataBytes *GetEventDataFromEvent(const Event *event_ptr); diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/FileSpecList.h b/contrib/llvm-project/lldb/include/lldb/Utility/FileSpecList.h index 49edc667ddd5..6eb3bb9971f1 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/FileSpecList.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/FileSpecList.h @@ -238,6 +238,10 @@ public: const_iterator begin() const { return m_files.begin(); } const_iterator end() const { return m_files.end(); } + llvm::iterator_range<const_iterator> files() const { + return llvm::make_range(begin(), end()); + } + protected: collection m_files; ///< A collection of FileSpec objects. }; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Listener.h b/contrib/llvm-project/lldb/include/lldb/Utility/Listener.h index daa7deb345f3..d48816ec0ea4 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Listener.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Listener.h @@ -94,8 +94,6 @@ public: size_t HandleBroadcastEvent(lldb::EventSP &event_sp); - void SetShadow(bool is_shadow) { m_is_shadow = is_shadow; } - private: // Classes that inherit from Listener can see and modify these struct BroadcasterInfo { @@ -127,12 +125,11 @@ private: std::string m_name; broadcaster_collection m_broadcasters; - std::recursive_mutex m_broadcasters_mutex; // Protects m_broadcasters + std::mutex m_broadcasters_mutex; // Protects m_broadcasters event_collection m_events; std::mutex m_events_mutex; // Protects m_broadcasters and m_events std::condition_variable m_events_condition; broadcaster_manager_collection m_broadcaster_managers; - bool m_is_shadow = false; void BroadcasterWillDestruct(Broadcaster *); diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Log.h b/contrib/llvm-project/lldb/include/lldb/Utility/Log.h index 1fe28d61b9da..27707c17f9b8 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Log.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Log.h @@ -112,6 +112,23 @@ private: static char ID; }; +/// A T-style log handler that multiplexes messages to two log handlers. +class TeeLogHandler : public LogHandler { +public: + TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler, + std::shared_ptr<LogHandler> second_log_handler); + + void Emit(llvm::StringRef message) override; + + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const LogHandler *obj) { return obj->isA(&ID); } + +private: + std::shared_ptr<LogHandler> m_first_log_handler; + std::shared_ptr<LogHandler> m_second_log_handler; + static char ID; +}; + class Log final { public: /// The underlying type of all log channel enums. Declare them as: @@ -373,4 +390,18 @@ template <typename Cat> Log *GetLog(Cat mask) { ::llvm::consumeError(::std::move(error_private)); \ } while (0) +// Write message to the verbose log, if error is set. In the log +// message refer to the error with {0}. Error is cleared regardless of +// whether logging is enabled. +#define LLDB_LOG_ERRORV(log, error, ...) \ + do { \ + ::lldb_private::Log *log_private = (log); \ + ::llvm::Error error_private = (error); \ + if (log_private && log_private->GetVerbose() && error_private) { \ + log_private->FormatError(::std::move(error_private), __FILE__, __func__, \ + __VA_ARGS__); \ + } else \ + ::llvm::consumeError(::std::move(error_private)); \ + } while (0) + #endif // LLDB_UTILITY_LOG_H diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/ProcessInfo.h b/contrib/llvm-project/lldb/include/lldb/Utility/ProcessInfo.h index 7fb5b37be0f4..78ade4bbb1ee 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/ProcessInfo.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/ProcessInfo.h @@ -15,6 +15,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/NameMatches.h" #include "lldb/Utility/StructuredData.h" +#include <optional> #include <vector> namespace lldb_private { @@ -139,11 +140,15 @@ protected: // to that process. class ProcessInstanceInfo : public ProcessInfo { public: + struct timespec { + time_t tv_sec = 0; + long int tv_usec = 0; + }; + ProcessInstanceInfo() = default; ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) - : ProcessInfo(name, arch, pid), m_euid(UINT32_MAX), m_egid(UINT32_MAX), - m_parent_pid(LLDB_INVALID_PROCESS_ID) {} + : ProcessInfo(name, arch, pid) {} void Clear() { ProcessInfo::Clear(); @@ -172,6 +177,76 @@ public: return m_parent_pid != LLDB_INVALID_PROCESS_ID; } + lldb::pid_t GetProcessGroupID() const { return m_process_group_id; } + + void SetProcessGroupID(lldb::pid_t pgrp) { m_process_group_id = pgrp; } + + bool ProcessGroupIDIsValid() const { + return m_process_group_id != LLDB_INVALID_PROCESS_ID; + } + + lldb::pid_t GetProcessSessionID() const { return m_process_session_id; } + + void SetProcessSessionID(lldb::pid_t session) { + m_process_session_id = session; + } + + bool ProcessSessionIDIsValid() const { + return m_process_session_id != LLDB_INVALID_PROCESS_ID; + } + + struct timespec GetUserTime() const { return m_user_time; } + + void SetUserTime(struct timespec utime) { m_user_time = utime; } + + bool UserTimeIsValid() const { + return m_user_time.tv_sec > 0 || m_user_time.tv_usec > 0; + } + + struct timespec GetSystemTime() const { return m_system_time; } + + void SetSystemTime(struct timespec stime) { m_system_time = stime; } + + bool SystemTimeIsValid() const { + return m_system_time.tv_sec > 0 || m_system_time.tv_usec > 0; + } + + struct timespec GetCumulativeUserTime() const { + return m_cumulative_user_time; + } + + void SetCumulativeUserTime(struct timespec cutime) { + m_cumulative_user_time = cutime; + } + + bool CumulativeUserTimeIsValid() const { + return m_cumulative_user_time.tv_sec > 0 || + m_cumulative_user_time.tv_usec > 0; + } + + struct timespec GetCumulativeSystemTime() const { + return m_cumulative_system_time; + } + + void SetCumulativeSystemTime(struct timespec cstime) { + m_cumulative_system_time = cstime; + } + + bool CumulativeSystemTimeIsValid() const { + return m_cumulative_system_time.tv_sec > 0 || + m_cumulative_system_time.tv_usec > 0; + } + + std::optional<int8_t> GetPriorityValue() const { return m_priority_value; } + + void SetPriorityValue(int8_t priority_value) { + m_priority_value = priority_value; + } + + void SetIsZombie(bool is_zombie) { m_zombie = is_zombie; } + + std::optional<bool> IsZombie() const { return m_zombie; } + void Dump(Stream &s, UserIDResolver &resolver) const; static void DumpTableHeader(Stream &s, bool show_args, bool verbose); @@ -183,6 +258,14 @@ protected: uint32_t m_euid = UINT32_MAX; uint32_t m_egid = UINT32_MAX; lldb::pid_t m_parent_pid = LLDB_INVALID_PROCESS_ID; + lldb::pid_t m_process_group_id = LLDB_INVALID_PROCESS_ID; + lldb::pid_t m_process_session_id = LLDB_INVALID_PROCESS_ID; + struct timespec m_user_time; + struct timespec m_system_time; + struct timespec m_cumulative_user_time; + struct timespec m_cumulative_system_time; + std::optional<int8_t> m_priority_value = std::nullopt; + std::optional<bool> m_zombie = std::nullopt; }; typedef std::vector<ProcessInstanceInfo> ProcessInstanceInfoList; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/RegularExpression.h b/contrib/llvm-project/lldb/include/lldb/Utility/RegularExpression.h index 415f1b58b111..e8bd47bb53c2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/RegularExpression.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/RegularExpression.h @@ -31,7 +31,13 @@ public: /// \param[in] string /// An llvm::StringRef that represents the regular expression to compile. // String is not referenced anymore after the object is constructed. - explicit RegularExpression(llvm::StringRef string); + // + /// \param[in] flags + /// An llvm::Regex::RegexFlags that modifies the matching behavior. The + /// default is NoFlags. + explicit RegularExpression( + llvm::StringRef string, + llvm::Regex::RegexFlags flags = llvm::Regex::NoFlags); ~RegularExpression() = default; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/Scalar.h b/contrib/llvm-project/lldb/include/lldb/Utility/Scalar.h index 8e087a5ddeb8..0d8eba3c9726 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/Scalar.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/Scalar.h @@ -71,6 +71,7 @@ public: : m_type(e_int), m_integer(std::move(v), false), m_float(0.0f) {} Scalar(llvm::APSInt v) : m_type(e_int), m_integer(std::move(v)), m_float(0.0f) {} + Scalar(llvm::APFloat v) : m_type(e_float), m_integer(0), m_float(v) {} bool SignExtend(uint32_t bit_pos); @@ -180,12 +181,20 @@ public: long double LongDouble(long double fail_value = 0.0) const; + llvm::APSInt GetAPSInt() const { return m_integer; } + + llvm::APFloat GetAPFloat() const { return m_float; } + Status SetValueFromCString(const char *s, lldb::Encoding encoding, size_t byte_size); Status SetValueFromData(const DataExtractor &data, lldb::Encoding encoding, size_t byte_size); + llvm::APFloat CreateAPFloatFromAPSInt(lldb::BasicType basic_type); + + llvm::APFloat CreateAPFloatFromAPFloat(lldb::BasicType basic_type); + protected: Scalar::Type m_type = e_void; llvm::APSInt m_integer; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/StreamString.h b/contrib/llvm-project/lldb/include/lldb/Utility/StreamString.h index 3d675caf8f3f..3287f328a1be 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/StreamString.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/StreamString.h @@ -20,6 +20,8 @@ namespace lldb_private { +class ScriptInterpreter; + class StreamString : public Stream { public: StreamString(bool colors = false); @@ -45,6 +47,8 @@ public: void FillLastLineToColumn(uint32_t column, char fill_char); protected: + friend class ScriptInterpreter; + std::string m_packet; size_t WriteImpl(const void *s, size_t length) override; }; diff --git a/contrib/llvm-project/lldb/include/lldb/Utility/SupportFile.h b/contrib/llvm-project/lldb/include/lldb/Utility/SupportFile.h index 0ea0ca4e7c97..334a0aaac2c2 100644 --- a/contrib/llvm-project/lldb/include/lldb/Utility/SupportFile.h +++ b/contrib/llvm-project/lldb/include/lldb/Utility/SupportFile.h @@ -30,11 +30,37 @@ public: virtual ~SupportFile() = default; - bool operator==(const SupportFile &other) const { - return m_file_spec == other.m_file_spec && m_checksum == other.m_checksum; - } + enum SupportFileEquality : uint8_t { + eEqualFileSpec = (1u << 1), + eEqualChecksum = (1u << 2), + eEqualChecksumIfSet = (1u << 3), + eEqualFileSpecAndChecksum = eEqualFileSpec | eEqualChecksum, + eEqualFileSpecAndChecksumIfSet = eEqualFileSpec | eEqualChecksumIfSet, + }; + + bool Equal(const SupportFile &other, + SupportFileEquality equality = eEqualFileSpecAndChecksum) const { + assert(!(equality & eEqualChecksum & eEqualChecksumIfSet) && + "eEqualChecksum and eEqualChecksumIfSet are mutually exclusive"); + + if (equality & eEqualFileSpec) { + if (m_file_spec != other.m_file_spec) + return false; + } - bool operator!=(const SupportFile &other) const { return !(*this == other); } + if (equality & eEqualChecksum) { + if (m_checksum != other.m_checksum) + return false; + } + + if (equality & eEqualChecksumIfSet) { + if (m_checksum && other.m_checksum) + if (m_checksum != other.m_checksum) + return false; + } + + return true; + } /// Return the file name only. Useful for resolving breakpoints by file name. const FileSpec &GetSpecOnly() const { return m_file_spec; }; diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-defines.h b/contrib/llvm-project/lldb/include/lldb/lldb-defines.h index 469be92eabec..c7bd019c5c90 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-defines.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-defines.h @@ -127,6 +127,11 @@ #define MAX_PATH 260 #endif +/// Address Mask +/// Bits not used for addressing are set to 1 in the mask; +/// all mask bits set is an invalid value. +#define LLDB_INVALID_ADDRESS_MASK UINT64_MAX + // ignore GCC function attributes #if defined(_MSC_VER) && !defined(__clang__) #define __attribute__(X) diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h index 44a596693e16..b2ef1f0edf57 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-enumerations.h @@ -651,6 +651,9 @@ enum CommandArgumentType { eArgTypeTargetID, eArgTypeStopHookID, eArgTypeCompletionType, + eArgTypeRemotePath, + eArgTypeRemoteFilename, + eArgTypeModule, eArgTypeLastArg // Always keep this entry as the last entry in this // enumeration!! }; @@ -1104,7 +1107,12 @@ enum MemberFunctionKind { }; /// String matching algorithm used by SBTarget. -enum MatchType { eMatchTypeNormal, eMatchTypeRegex, eMatchTypeStartsWith }; +enum MatchType { + eMatchTypeNormal, + eMatchTypeRegex, + eMatchTypeStartsWith, + eMatchTypeRegexInsensitive +}; /// Bitmask that describes details about a type. FLAGS_ENUM(TypeFlags){ @@ -1305,6 +1313,53 @@ enum CompletionType { eTerminatorCompletion = (1ul << 27) }; +/// Specifies if children need to be re-computed +/// after a call to \ref SyntheticChildrenFrontEnd::Update. +enum ChildCacheState { + eRefetch = 0, ///< Children need to be recomputed dynamically. + + eReuse = 1, ///< Children did not change and don't need to be recomputed; + ///< re-use what we computed the last time we called Update. +}; + +enum SymbolDownload { + eSymbolDownloadOff = 0, + eSymbolDownloadBackground = 1, + eSymbolDownloadForeground = 2, +}; + +/// Used in the SBProcess AddressMask/FixAddress methods. +enum AddressMaskType { + eAddressMaskTypeCode = 0, + eAddressMaskTypeData, + eAddressMaskTypeAny, + eAddressMaskTypeAll = eAddressMaskTypeAny +}; + +/// Used in the SBProcess AddressMask/FixAddress methods. +enum AddressMaskRange { + eAddressMaskRangeLow = 0, + eAddressMaskRangeHigh, + eAddressMaskRangeAny, + eAddressMaskRangeAll = eAddressMaskRangeAny, +}; + +/// Used by the debugger to indicate which events are being broadcasted. +enum DebuggerBroadcastBit { + eBroadcastBitProgress = (1 << 0), + eBroadcastBitWarning = (1 << 1), + eBroadcastBitError = (1 << 2), + eBroadcastSymbolChange = (1 << 3), + eBroadcastBitProgressCategory = (1 << 4), +}; + +/// Used for expressing severity in logs and diagnostics. +enum Severity { + eSeverityError, + eSeverityWarning, + eSeverityInfo, // Equivalent to Remark used in clang. +}; + } // namespace lldb #endif // LLDB_LLDB_ENUMERATIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-forward.h b/contrib/llvm-project/lldb/include/lldb/lldb-forward.h index d89ad2151221..1024501e05bc 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-forward.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-forward.h @@ -19,6 +19,8 @@ class ASTResultSynthesizer; class ASTStructExtractor; class Address; class AddressRange; +class AddressRanges; +class AddressRangeList; class AddressResolver; class ArchSpec; class Architecture; @@ -180,6 +182,7 @@ class RegisterTypeBuilder; class RegisterValue; class RegularExpression; class RichManglingContext; +class SaveCoreOptions; class Scalar; class ScriptInterpreter; class ScriptInterpreterLocker; @@ -187,6 +190,7 @@ class ScriptedMetadata; class ScriptedPlatformInterface; class ScriptedProcessInterface; class ScriptedThreadInterface; +class ScriptedThreadPlanInterface; class ScriptedSyntheticChildren; class SearchFilter; class Section; @@ -298,6 +302,7 @@ struct CompilerContext; struct LineEntry; struct PropertyDefinition; struct ScriptSummaryFormat; +struct StatisticsOptions; struct StringSummaryFormat; template <unsigned N> class StreamBuffer; @@ -307,6 +312,7 @@ template <unsigned N> class StreamBuffer; namespace lldb { typedef std::shared_ptr<lldb_private::ABI> ABISP; +typedef std::unique_ptr<lldb_private::AddressRange> AddressRangeUP; typedef std::shared_ptr<lldb_private::Baton> BatonSP; typedef std::shared_ptr<lldb_private::Block> BlockSP; typedef std::shared_ptr<lldb_private::Breakpoint> BreakpointSP; @@ -402,6 +408,8 @@ typedef std::unique_ptr<lldb_private::ScriptedProcessInterface> ScriptedProcessInterfaceUP; typedef std::shared_ptr<lldb_private::ScriptedThreadInterface> ScriptedThreadInterfaceSP; +typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface> + ScriptedThreadPlanInterfaceSP; typedef std::shared_ptr<lldb_private::Section> SectionSP; typedef std::unique_ptr<lldb_private::SectionList> SectionListUP; typedef std::weak_ptr<lldb_private::Section> SectionWP; diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-private-enumerations.h b/contrib/llvm-project/lldb/include/lldb/lldb-private-enumerations.h index 5f1597200a83..9d18316dcea2 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-private-enumerations.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-private-enumerations.h @@ -9,6 +9,8 @@ #ifndef LLDB_LLDB_PRIVATE_ENUMERATIONS_H #define LLDB_LLDB_PRIVATE_ENUMERATIONS_H +#include "lldb/lldb-enumerations.h" +#include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatProviders.h" #include "llvm/Support/raw_ostream.h" @@ -107,7 +109,12 @@ enum ArgumentRepetitionType { // optional }; -enum SortOrder { eSortOrderNone, eSortOrderByAddress, eSortOrderByName }; +enum SortOrder { + eSortOrderNone, + eSortOrderByAddress, + eSortOrderByName, + eSortOrderBySize +}; // LazyBool is for boolean values that need to be calculated lazily. Values // start off set to eLazyBoolCalculate, and then they can be calculated once @@ -191,8 +198,7 @@ enum class CompilerContextKind : uint16_t { TranslationUnit = 1, Module = 1 << 1, Namespace = 1 << 2, - Class = 1 << 3, - Struct = 1 << 4, + ClassOrStruct = 1 << 3, Union = 1 << 5, Function = 1 << 6, Variable = 1 << 7, @@ -204,10 +210,12 @@ enum class CompilerContextKind : uint16_t { /// Match 0..n nested modules. AnyModule = Any | Module, /// Match any type. - AnyType = Any | Class | Struct | Union | Enum | Typedef | Builtin, + AnyType = Any | ClassOrStruct | Union | Enum | Typedef | Builtin, /// Math any declaration context. - AnyDeclContext = Any | Namespace | Class | Struct | Union | Enum | Function + AnyDeclContext = Any | Namespace | ClassOrStruct | Union | Enum | Function, + LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/AnyDeclContext), }; +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); // Enumerations that can be used to specify the kind of metric we're looking at // when collecting stats. @@ -234,6 +242,13 @@ enum LoadDependentFiles { eLoadDependentsNo, }; +/// Useful for callbacks whose return type indicates +/// whether to continue iteration or short-circuit. +enum class IterationAction { + Continue = 0, + Stop, +}; + inline std::string GetStatDescription(lldb_private::StatisticKind K) { switch (K) { case StatisticKind::ExpressionSuccessful: @@ -282,4 +297,30 @@ enum InterruptionControl : bool { DoNotAllowInterruption = false, }; +/// The hardware and native stub capabilities for a given target, +/// for translating a user's watchpoint request into hardware +/// capable watchpoint resources. +FLAGS_ENUM(WatchpointHardwareFeature){ + /// lldb will fall back to a default that assumes the target + /// can watch up to pointer-size power-of-2 regions, aligned to + /// power-of-2. + eWatchpointHardwareFeatureUnknown = (1u << 0), + + /// Intel systems can watch 1, 2, 4, or 8 bytes (in 64-bit targets), + /// aligned naturally. + eWatchpointHardwareX86 = (1u << 1), + + /// ARM systems with Byte Address Select watchpoints + /// can watch any consecutive series of bytes up to the + /// size of a pointer (4 or 8 bytes), at a pointer-size + /// alignment. + eWatchpointHardwareArmBAS = (1u << 2), + + /// ARM systems with MASK watchpoints can watch any power-of-2 + /// sized region from 8 bytes to 2 gigabytes, aligned to that + /// same power-of-2 alignment. + eWatchpointHardwareArmMASK = (1u << 3), +}; +LLDB_MARK_AS_BITMASK_ENUM(WatchpointHardwareFeature) + #endif // LLDB_LLDB_PRIVATE_ENUMERATIONS_H diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-private-interfaces.h b/contrib/llvm-project/lldb/include/lldb/lldb-private-interfaces.h index 53d5fbb84cc9..10eaf1e6a5ad 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-private-interfaces.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-private-interfaces.h @@ -9,6 +9,7 @@ #ifndef LLDB_LLDB_PRIVATE_INTERFACES_H #define LLDB_LLDB_PRIVATE_INTERFACES_H +#include "lldb/Symbol/SaveCoreOptions.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" @@ -55,8 +56,7 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)( const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset); typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, Status &error); typedef EmulateInstruction *(*EmulateInstructionCreateInstance)( const ArchSpec &arch, InstructionType inst_type); @@ -99,10 +99,10 @@ typedef std::optional<FileSpec> (*SymbolLocatorLocateExecutableSymbolFile)( typedef bool (*SymbolLocatorDownloadObjectAndSymbolFile)( ModuleSpec &module_spec, Status &error, bool force_lookup, bool copy_executable); -typedef bool (*BreakpointHitCallback)(void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); +using BreakpointHitCallback = + std::function<bool(void *baton, StoppointCallbackContext *context, + lldb::user_id_t break_id, lldb::user_id_t break_loc_id)>; + typedef bool (*WatchpointHitCallback)(void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id); diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-private-types.h b/contrib/llvm-project/lldb/include/lldb/lldb-private-types.h index 7d301666df1a..055eea9f6456 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-private-types.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-private-types.h @@ -96,6 +96,25 @@ struct RegisterSet { const uint32_t *registers; }; +/// A type-erased pair of llvm::dwarf::SourceLanguageName and version. +struct SourceLanguage { + SourceLanguage() = default; + SourceLanguage(lldb::LanguageType language_type); + SourceLanguage(uint16_t name, uint32_t version) + : name(name), version(version) {} + SourceLanguage(std::optional<std::pair<uint16_t, uint32_t>> name_vers) + : name(name_vers ? name_vers->first : 0), + version(name_vers ? name_vers->second : 0) {} + operator bool() const { return name > 0; } + lldb::LanguageType AsLanguageType() const; + llvm::StringRef GetDescription() const; + bool IsC() const; + bool IsObjC() const; + bool IsCPlusPlus() const; + uint16_t name = 0; + uint32_t version = 0; +}; + struct OptionEnumValueElement { int64_t value; const char *string_value; diff --git a/contrib/llvm-project/lldb/include/lldb/lldb-types.h b/contrib/llvm-project/lldb/include/lldb/lldb-types.h index d60686e33142..d88b8232ee6b 100644 --- a/contrib/llvm-project/lldb/include/lldb/lldb-types.h +++ b/contrib/llvm-project/lldb/include/lldb/lldb-types.h @@ -68,6 +68,7 @@ typedef int pipe_t; // Host pipe type #define LLDB_INVALID_PROCESS ((lldb::process_t)-1) #define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL) #define LLDB_INVALID_PIPE ((lldb::pipe_t)-1) +#define LLDB_INVALID_CALLBACK_TOKEN ((lldb::callback_token_t) - 1) typedef void (*LogOutputCallback)(const char *, void *baton); typedef bool (*CommandOverrideCallback)(void *baton, const char **argv); @@ -77,6 +78,7 @@ typedef bool (*ExpressionCancelCallback)(ExpressionEvaluationPhase phase, typedef void *ScriptObjectPtr; typedef uint64_t addr_t; +typedef int32_t callback_token_t; typedef uint64_t user_id_t; typedef uint64_t pid_t; typedef uint64_t tid_t; diff --git a/contrib/llvm-project/lldb/source/API/SBAddressRange.cpp b/contrib/llvm-project/lldb/source/API/SBAddressRange.cpp new file mode 100644 index 000000000000..5834ebe5e63c --- /dev/null +++ b/contrib/llvm-project/lldb/source/API/SBAddressRange.cpp @@ -0,0 +1,96 @@ +//===-- SBAddressRange.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBAddressRange.h" +#include "Utils.h" +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/Instrumentation.h" +#include "lldb/Utility/Stream.h" +#include <cstddef> +#include <memory> + +using namespace lldb; +using namespace lldb_private; + +SBAddressRange::SBAddressRange() + : m_opaque_up(std::make_unique<AddressRange>()) { + LLDB_INSTRUMENT_VA(this); +} + +SBAddressRange::SBAddressRange(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBAddressRange::SBAddressRange(lldb::SBAddress addr, lldb::addr_t byte_size) + : m_opaque_up(std::make_unique<AddressRange>(addr.ref(), byte_size)) { + LLDB_INSTRUMENT_VA(this, addr, byte_size); +} + +SBAddressRange::~SBAddressRange() = default; + +const SBAddressRange &SBAddressRange::operator=(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +bool SBAddressRange::operator==(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + return ref().operator==(rhs.ref()); +} + +bool SBAddressRange::operator!=(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + return !(*this == rhs); +} + +void SBAddressRange::Clear() { + LLDB_INSTRUMENT_VA(this); + + ref().Clear(); +} + +bool SBAddressRange::IsValid() const { + LLDB_INSTRUMENT_VA(this); + + return ref().IsValid(); +} + +lldb::SBAddress SBAddressRange::GetBaseAddress() const { + LLDB_INSTRUMENT_VA(this); + + return lldb::SBAddress(ref().GetBaseAddress()); +} + +lldb::addr_t SBAddressRange::GetByteSize() const { + LLDB_INSTRUMENT_VA(this); + + return ref().GetByteSize(); +} + +bool SBAddressRange::GetDescription(SBStream &description, + const SBTarget target) { + LLDB_INSTRUMENT_VA(this, description, target); + + return ref().GetDescription(&description.ref(), target.GetSP().get()); +} + +lldb_private::AddressRange &SBAddressRange::ref() const { + assert(m_opaque_up && "opaque pointer must always be valid"); + return *m_opaque_up; +} diff --git a/contrib/llvm-project/lldb/source/API/SBAddressRangeList.cpp b/contrib/llvm-project/lldb/source/API/SBAddressRangeList.cpp new file mode 100644 index 000000000000..957155d5125e --- /dev/null +++ b/contrib/llvm-project/lldb/source/API/SBAddressRangeList.cpp @@ -0,0 +1,99 @@ +//===-- SBAddressRangeList.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBAddressRangeList.h" +#include "Utils.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" +#include "lldb/Core/AddressRangeListImpl.h" +#include "lldb/Utility/Instrumentation.h" +#include "lldb/Utility/Stream.h" + +#include <memory> + +using namespace lldb; +using namespace lldb_private; + +SBAddressRangeList::SBAddressRangeList() + : m_opaque_up(std::make_unique<AddressRangeListImpl>()) { + LLDB_INSTRUMENT_VA(this); +} + +SBAddressRangeList::SBAddressRangeList(const SBAddressRangeList &rhs) + : m_opaque_up(std::make_unique<AddressRangeListImpl>(*rhs.m_opaque_up)) { + LLDB_INSTRUMENT_VA(this, rhs); +} + +SBAddressRangeList::~SBAddressRangeList() = default; + +const SBAddressRangeList & +SBAddressRangeList::operator=(const SBAddressRangeList &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + ref() = rhs.ref(); + return *this; +} + +uint32_t SBAddressRangeList::GetSize() const { + LLDB_INSTRUMENT_VA(this); + + return ref().GetSize(); +} + +SBAddressRange SBAddressRangeList::GetAddressRangeAtIndex(uint64_t idx) { + LLDB_INSTRUMENT_VA(this, idx); + + SBAddressRange sb_addr_range; + (*sb_addr_range.m_opaque_up) = ref().GetAddressRangeAtIndex(idx); + return sb_addr_range; +} + +void SBAddressRangeList::Clear() { + LLDB_INSTRUMENT_VA(this); + + ref().Clear(); +} + +void SBAddressRangeList::Append(const SBAddressRange &sb_addr_range) { + LLDB_INSTRUMENT_VA(this, sb_addr_range); + + ref().Append(*sb_addr_range.m_opaque_up); +} + +void SBAddressRangeList::Append(const SBAddressRangeList &sb_addr_range_list) { + LLDB_INSTRUMENT_VA(this, sb_addr_range_list); + + ref().Append(*sb_addr_range_list.m_opaque_up); +} + +bool SBAddressRangeList::GetDescription(SBStream &description, + const SBTarget &target) { + LLDB_INSTRUMENT_VA(this, description, target); + + const uint32_t num_ranges = GetSize(); + bool is_first = true; + Stream &stream = description.ref(); + stream << "["; + for (uint32_t i = 0; i < num_ranges; ++i) { + if (is_first) { + is_first = false; + } else { + stream.Printf(", "); + } + GetAddressRangeAtIndex(i).GetDescription(description, target); + } + stream << "]"; + return true; +} + +lldb_private::AddressRangeListImpl &SBAddressRangeList::ref() const { + assert(m_opaque_up && "opaque pointer must always be valid"); + return *m_opaque_up; +} diff --git a/contrib/llvm-project/lldb/source/API/SBAttachInfo.cpp b/contrib/llvm-project/lldb/source/API/SBAttachInfo.cpp index 8ce1f1d65c49..a9f712c79c7f 100644 --- a/contrib/llvm-project/lldb/source/API/SBAttachInfo.cpp +++ b/contrib/llvm-project/lldb/source/API/SBAttachInfo.cpp @@ -266,13 +266,7 @@ SBListener SBAttachInfo::GetShadowListener() { void SBAttachInfo::SetShadowListener(SBListener &listener) { LLDB_INSTRUMENT_VA(this, listener); - ListenerSP listener_sp = listener.GetSP(); - if (listener_sp && listener.IsValid()) - listener_sp->SetShadow(true); - else - listener_sp = nullptr; - - m_opaque_sp->SetShadowListener(listener_sp); + m_opaque_sp->SetShadowListener(listener.GetSP()); } const char *SBAttachInfo::GetScriptedProcessClassName() const { diff --git a/contrib/llvm-project/lldb/source/API/SBBlock.cpp b/contrib/llvm-project/lldb/source/API/SBBlock.cpp index 7d7565340836..2577b14920f0 100644 --- a/contrib/llvm-project/lldb/source/API/SBBlock.cpp +++ b/contrib/llvm-project/lldb/source/API/SBBlock.cpp @@ -13,6 +13,7 @@ #include "lldb/API/SBStream.h" #include "lldb/API/SBValue.h" #include "lldb/Core/AddressRange.h" +#include "lldb/Core/AddressRangeListImpl.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" @@ -219,6 +220,15 @@ lldb::SBAddress SBBlock::GetRangeEndAddress(uint32_t idx) { return sb_addr; } +lldb::SBAddressRangeList SBBlock::GetRanges() { + LLDB_INSTRUMENT_VA(this); + + lldb::SBAddressRangeList sb_ranges; + if (m_opaque_ptr) + sb_ranges.m_opaque_up->ref() = m_opaque_ptr->GetRanges(); + return sb_ranges; +} + uint32_t SBBlock::GetRangeIndexForBlockAddress(lldb::SBAddress block_addr) { LLDB_INSTRUMENT_VA(this, block_addr); diff --git a/contrib/llvm-project/lldb/source/API/SBBreakpoint.cpp b/contrib/llvm-project/lldb/source/API/SBBreakpoint.cpp index f1fb6f904f5f..3d908047f945 100644 --- a/contrib/llvm-project/lldb/source/API/SBBreakpoint.cpp +++ b/contrib/llvm-project/lldb/source/API/SBBreakpoint.cpp @@ -714,7 +714,7 @@ void SBBreakpoint::GetNames(SBStringList &names) { bkpt_sp->GetTarget().GetAPIMutex()); std::vector<std::string> names_vec; bkpt_sp->GetNames(names_vec); - for (std::string name : names_vec) { + for (const std::string &name : names_vec) { names.AppendString(name.c_str()); } } diff --git a/contrib/llvm-project/lldb/source/API/SBBreakpointOptionCommon.h b/contrib/llvm-project/lldb/source/API/SBBreakpointOptionCommon.h index 0ceb90290de5..3296e26698ff 100644 --- a/contrib/llvm-project/lldb/source/API/SBBreakpointOptionCommon.h +++ b/contrib/llvm-project/lldb/source/API/SBBreakpointOptionCommon.h @@ -1,4 +1,4 @@ -//===-- SBBreakpointOptionCommon.h ------------------------------------------*- C++ -*-===// +//===-- SBBreakpointOptionCommon.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. diff --git a/contrib/llvm-project/lldb/source/API/SBCommandInterpreter.cpp b/contrib/llvm-project/lldb/source/API/SBCommandInterpreter.cpp index c3cbb00145ed..7a3547328368 100644 --- a/contrib/llvm-project/lldb/source/API/SBCommandInterpreter.cpp +++ b/contrib/llvm-project/lldb/source/API/SBCommandInterpreter.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "lldb/Utility/StructuredData.h" #include "lldb/lldb-types.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -512,7 +513,8 @@ SBBroadcaster SBCommandInterpreter::GetBroadcaster() { const char *SBCommandInterpreter::GetBroadcasterClass() { LLDB_INSTRUMENT(); - return CommandInterpreter::GetStaticBroadcasterClass().AsCString(); + return ConstString(CommandInterpreter::GetStaticBroadcasterClass()) + .AsCString(); } const char *SBCommandInterpreter::GetArgumentTypeAsCString( @@ -557,6 +559,34 @@ bool SBCommandInterpreter::SetCommandOverrideCallback( return false; } +SBStructuredData SBCommandInterpreter::GetStatistics() { + LLDB_INSTRUMENT_VA(this); + + SBStructuredData data; + if (!IsValid()) + return data; + + std::string json_str = + llvm::formatv("{0:2}", m_opaque_ptr->GetStatistics()).str(); + data.m_impl_up->SetObjectSP(StructuredData::ParseJSON(json_str)); + return data; +} + +SBStructuredData SBCommandInterpreter::GetTranscript() { + LLDB_INSTRUMENT_VA(this); + + SBStructuredData data; + if (IsValid()) + // A deep copy is performed by `std::make_shared` on the + // `StructuredData::Array`, via its implicitly-declared copy constructor. + // This ensures thread-safety between the user changing the returned + // `SBStructuredData` and the `CommandInterpreter` changing its internal + // `m_transcript`. + data.m_impl_up->SetObjectSP( + std::make_shared<StructuredData::Array>(m_opaque_ptr->GetTranscript())); + return data; +} + lldb::SBCommand SBCommandInterpreter::AddMultiwordCommand(const char *name, const char *help) { LLDB_INSTRUMENT_VA(this, name, help); diff --git a/contrib/llvm-project/lldb/source/API/SBCommandInterpreterRunOptions.cpp b/contrib/llvm-project/lldb/source/API/SBCommandInterpreterRunOptions.cpp index 6c6b2aa15a79..0c7581d6f1f5 100644 --- a/contrib/llvm-project/lldb/source/API/SBCommandInterpreterRunOptions.cpp +++ b/contrib/llvm-project/lldb/source/API/SBCommandInterpreterRunOptions.cpp @@ -164,6 +164,18 @@ void SBCommandInterpreterRunOptions::SetSpawnThread(bool spawn_thread) { m_opaque_up->SetSpawnThread(spawn_thread); } +bool SBCommandInterpreterRunOptions::GetAllowRepeats() const { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up->GetAllowRepeats(); +} + +void SBCommandInterpreterRunOptions::SetAllowRepeats(bool allow_repeats) { + LLDB_INSTRUMENT_VA(this, allow_repeats); + + m_opaque_up->SetAllowRepeats(allow_repeats); +} + lldb_private::CommandInterpreterRunOptions * SBCommandInterpreterRunOptions::get() const { return m_opaque_up.get(); diff --git a/contrib/llvm-project/lldb/source/API/SBCommunication.cpp b/contrib/llvm-project/lldb/source/API/SBCommunication.cpp index f93898718be6..ee33e2abd854 100644 --- a/contrib/llvm-project/lldb/source/API/SBCommunication.cpp +++ b/contrib/llvm-project/lldb/source/API/SBCommunication.cpp @@ -170,5 +170,6 @@ SBBroadcaster SBCommunication::GetBroadcaster() { const char *SBCommunication::GetBroadcasterClass() { LLDB_INSTRUMENT(); - return ThreadedCommunication::GetStaticBroadcasterClass().AsCString(); + return ConstString(ThreadedCommunication::GetStaticBroadcasterClass()) + .AsCString(); } diff --git a/contrib/llvm-project/lldb/source/API/SBDebugger.cpp b/contrib/llvm-project/lldb/source/API/SBDebugger.cpp index fbcf30e67fc1..29da7d33dd80 100644 --- a/contrib/llvm-project/lldb/source/API/SBDebugger.cpp +++ b/contrib/llvm-project/lldb/source/API/SBDebugger.cpp @@ -112,7 +112,7 @@ SBDebugger &SBDebugger::operator=(const SBDebugger &rhs) { const char *SBDebugger::GetBroadcasterClass() { LLDB_INSTRUMENT(); - return Debugger::GetStaticBroadcasterClass().AsCString(); + return ConstString(Debugger::GetStaticBroadcasterClass()).AsCString(); } const char *SBDebugger::GetProgressFromEvent(const lldb::SBEvent &event, @@ -1695,6 +1695,26 @@ void SBDebugger::SetDestroyCallback( } } +lldb::callback_token_t +SBDebugger::AddDestroyCallback(lldb::SBDebuggerDestroyCallback destroy_callback, + void *baton) { + LLDB_INSTRUMENT_VA(this, destroy_callback, baton); + + if (m_opaque_sp) + return m_opaque_sp->AddDestroyCallback(destroy_callback, baton); + + return LLDB_INVALID_CALLBACK_TOKEN; +} + +bool SBDebugger::RemoveDestroyCallback(lldb::callback_token_t token) { + LLDB_INSTRUMENT_VA(this, token); + + if (m_opaque_sp) + return m_opaque_sp->RemoveDestroyCallback(token); + + return false; +} + SBTrace SBDebugger::LoadTraceFromFile(SBError &error, const SBFileSpec &trace_description_file) { @@ -1722,3 +1742,7 @@ bool SBDebugger::InterruptRequested() { return m_opaque_sp->InterruptRequested(); return false; } + +bool SBDebugger::SupportsLanguage(lldb::LanguageType language) { + return TypeSystem::SupportsLanguageStatic(language); +} diff --git a/contrib/llvm-project/lldb/source/API/SBEvent.cpp b/contrib/llvm-project/lldb/source/API/SBEvent.cpp index f12df2939420..aa9c0ff097d4 100644 --- a/contrib/llvm-project/lldb/source/API/SBEvent.cpp +++ b/contrib/llvm-project/lldb/source/API/SBEvent.cpp @@ -24,7 +24,8 @@ using namespace lldb_private; SBEvent::SBEvent() { LLDB_INSTRUMENT_VA(this); } SBEvent::SBEvent(uint32_t event_type, const char *cstr, uint32_t cstr_len) - : m_event_sp(new Event(event_type, new EventDataBytes(cstr, cstr_len))), + : m_event_sp(new Event( + event_type, new EventDataBytes(llvm::StringRef(cstr, cstr_len)))), m_opaque_ptr(m_event_sp.get()) { LLDB_INSTRUMENT_VA(this, event_type, cstr, cstr_len); } @@ -94,7 +95,8 @@ const char *SBEvent::GetBroadcasterClass() const { const Event *lldb_event = get(); if (lldb_event) - return lldb_event->GetBroadcaster()->GetBroadcasterClass().AsCString(); + return ConstString(lldb_event->GetBroadcaster()->GetBroadcasterClass()) + .AsCString(); else return "unknown class"; } diff --git a/contrib/llvm-project/lldb/source/API/SBExpressionOptions.cpp b/contrib/llvm-project/lldb/source/API/SBExpressionOptions.cpp index bd81a04596b1..15ed403eaaea 100644 --- a/contrib/llvm-project/lldb/source/API/SBExpressionOptions.cpp +++ b/contrib/llvm-project/lldb/source/API/SBExpressionOptions.cpp @@ -156,6 +156,13 @@ void SBExpressionOptions::SetLanguage(lldb::LanguageType language) { m_opaque_up->SetLanguage(language); } +void SBExpressionOptions::SetLanguage(lldb::SBSourceLanguageName name, + uint32_t version) { + LLDB_INSTRUMENT_VA(this, name, version); + + m_opaque_up->SetLanguage(name, version); +} + void SBExpressionOptions::SetCancelCallback( lldb::ExpressionCancelCallback callback, void *baton) { LLDB_INSTRUMENT_VA(this, callback, baton); diff --git a/contrib/llvm-project/lldb/source/API/SBFrame.cpp b/contrib/llvm-project/lldb/source/API/SBFrame.cpp index a16bbc2ae756..47fc88625e30 100644 --- a/contrib/llvm-project/lldb/source/API/SBFrame.cpp +++ b/contrib/llvm-project/lldb/source/API/SBFrame.cpp @@ -1024,10 +1024,10 @@ SBValue SBFrame::EvaluateExpression(const char *expr) { options.SetFetchDynamicValue(fetch_dynamic_value); options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); - if (target->GetLanguage() != eLanguageTypeUnknown) - options.SetLanguage(target->GetLanguage()); - else - options.SetLanguage(frame->GetLanguage()); + SourceLanguage language = target->GetLanguage(); + if (!language) + language = frame->GetLanguage(); + options.SetLanguage((SBSourceLanguageName)language.name, language.version); return EvaluateExpression(expr, options); } else { Status error; @@ -1053,10 +1053,12 @@ SBFrame::EvaluateExpression(const char *expr, StackFrame *frame = exe_ctx.GetFramePtr(); Target *target = exe_ctx.GetTargetPtr(); - if (target && target->GetLanguage() != eLanguageTypeUnknown) - options.SetLanguage(target->GetLanguage()); - else if (frame) - options.SetLanguage(frame->GetLanguage()); + SourceLanguage language; + if (target) + language = target->GetLanguage(); + if (!language && frame) + language = frame->GetLanguage(); + options.SetLanguage((SBSourceLanguageName)language.name, language.version); return EvaluateExpression(expr, options); } @@ -1074,10 +1076,12 @@ SBValue SBFrame::EvaluateExpression(const char *expr, options.SetIgnoreBreakpoints(true); StackFrame *frame = exe_ctx.GetFramePtr(); Target *target = exe_ctx.GetTargetPtr(); - if (target && target->GetLanguage() != eLanguageTypeUnknown) - options.SetLanguage(target->GetLanguage()); - else if (frame) - options.SetLanguage(frame->GetLanguage()); + SourceLanguage language; + if (target) + language = target->GetLanguage(); + if (!language && frame) + language = frame->GetLanguage(); + options.SetLanguage((SBSourceLanguageName)language.name, language.version); return EvaluateExpression(expr, options); } @@ -1218,7 +1222,7 @@ lldb::LanguageType SBFrame::GuessLanguage() const { if (stop_locker.TryLock(&process->GetRunLock())) { frame = exe_ctx.GetFramePtr(); if (frame) { - return frame->GuessLanguage(); + return frame->GuessLanguage().AsLanguageType(); } } } diff --git a/contrib/llvm-project/lldb/source/API/SBFunction.cpp b/contrib/llvm-project/lldb/source/API/SBFunction.cpp index a01c7f79bbd3..6a97352fc2c2 100644 --- a/contrib/llvm-project/lldb/source/API/SBFunction.cpp +++ b/contrib/llvm-project/lldb/source/API/SBFunction.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBFunction.h" +#include "lldb/API/SBAddressRange.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Core/Disassembler.h" @@ -160,6 +161,19 @@ SBAddress SBFunction::GetEndAddress() { return addr; } +lldb::SBAddressRangeList SBFunction::GetRanges() { + LLDB_INSTRUMENT_VA(this); + + lldb::SBAddressRangeList ranges; + if (m_opaque_ptr) { + lldb::SBAddressRange range; + (*range.m_opaque_up) = m_opaque_ptr->GetAddressRange(); + ranges.Append(std::move(range)); + } + + return ranges; +} + const char *SBFunction::GetArgumentName(uint32_t arg_idx) { LLDB_INSTRUMENT_VA(this, arg_idx); diff --git a/contrib/llvm-project/lldb/source/API/SBLanguageRuntime.cpp b/contrib/llvm-project/lldb/source/API/SBLanguageRuntime.cpp index d571f282fce0..958652ab6f13 100644 --- a/contrib/llvm-project/lldb/source/API/SBLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/API/SBLanguageRuntime.cpp @@ -26,3 +26,43 @@ SBLanguageRuntime::GetNameForLanguageType(lldb::LanguageType language) { return Language::GetNameForLanguageType(language); } + +bool SBLanguageRuntime::LanguageIsCPlusPlus(lldb::LanguageType language) { + return Language::LanguageIsCPlusPlus(language); +} + +bool SBLanguageRuntime::LanguageIsObjC(lldb::LanguageType language) { + return Language::LanguageIsObjC(language); +} + +bool SBLanguageRuntime::LanguageIsCFamily(lldb::LanguageType language) { + return Language::LanguageIsCFamily(language); +} + +bool SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow( + lldb::LanguageType language) { + if (Language *lang_plugin = Language::FindPlugin(language)) + return lang_plugin->SupportsExceptionBreakpointsOnThrow(); + return false; +} + +bool SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch( + lldb::LanguageType language) { + if (Language *lang_plugin = Language::FindPlugin(language)) + return lang_plugin->SupportsExceptionBreakpointsOnCatch(); + return false; +} + +const char * +SBLanguageRuntime::GetThrowKeywordForLanguage(lldb::LanguageType language) { + if (Language *lang_plugin = Language::FindPlugin(language)) + return ConstString(lang_plugin->GetThrowKeyword()).AsCString(); + return nullptr; +} + +const char * +SBLanguageRuntime::GetCatchKeywordForLanguage(lldb::LanguageType language) { + if (Language *lang_plugin = Language::FindPlugin(language)) + return ConstString(lang_plugin->GetCatchKeyword()).AsCString(); + return nullptr; +} diff --git a/contrib/llvm-project/lldb/source/API/SBLaunchInfo.cpp b/contrib/llvm-project/lldb/source/API/SBLaunchInfo.cpp index d5f935083e6c..d6b52e8a67a4 100644 --- a/contrib/llvm-project/lldb/source/API/SBLaunchInfo.cpp +++ b/contrib/llvm-project/lldb/source/API/SBLaunchInfo.cpp @@ -402,11 +402,5 @@ SBListener SBLaunchInfo::GetShadowListener() { void SBLaunchInfo::SetShadowListener(SBListener &listener) { LLDB_INSTRUMENT_VA(this, listener); - ListenerSP listener_sp = listener.GetSP(); - if (listener_sp && listener.IsValid()) - listener_sp->SetShadow(true); - else - listener_sp = nullptr; - - m_opaque_sp->SetShadowListener(listener_sp); + m_opaque_sp->SetShadowListener(listener.GetSP()); } diff --git a/contrib/llvm-project/lldb/source/API/SBLineEntry.cpp b/contrib/llvm-project/lldb/source/API/SBLineEntry.cpp index 28d12e65fdaf..216ea6d18eab 100644 --- a/contrib/llvm-project/lldb/source/API/SBLineEntry.cpp +++ b/contrib/llvm-project/lldb/source/API/SBLineEntry.cpp @@ -67,6 +67,21 @@ SBAddress SBLineEntry::GetEndAddress() const { return sb_address; } +SBAddress SBLineEntry::GetSameLineContiguousAddressRangeEnd( + bool include_inlined_functions) const { + LLDB_INSTRUMENT_VA(this); + + SBAddress sb_address; + if (m_opaque_up) { + AddressRange line_range = m_opaque_up->GetSameLineContiguousAddressRange( + include_inlined_functions); + + sb_address.SetAddress(line_range.GetBaseAddress()); + sb_address.OffsetAddress(line_range.GetByteSize()); + } + return sb_address; +} + bool SBLineEntry::IsValid() const { LLDB_INSTRUMENT_VA(this); return this->operator bool(); @@ -81,8 +96,8 @@ SBFileSpec SBLineEntry::GetFileSpec() const { LLDB_INSTRUMENT_VA(this); SBFileSpec sb_file_spec; - if (m_opaque_up.get() && m_opaque_up->file) - sb_file_spec.SetFileSpec(m_opaque_up->file); + if (m_opaque_up.get() && m_opaque_up->GetFile()) + sb_file_spec.SetFileSpec(m_opaque_up->GetFile()); return sb_file_spec; } @@ -109,9 +124,9 @@ void SBLineEntry::SetFileSpec(lldb::SBFileSpec filespec) { LLDB_INSTRUMENT_VA(this, filespec); if (filespec.IsValid()) - ref().file = filespec.ref(); + ref().file_sp = std::make_shared<SupportFile>(filespec.ref()); else - ref().file.Clear(); + ref().file_sp = std::make_shared<SupportFile>(); } void SBLineEntry::SetLine(uint32_t line) { LLDB_INSTRUMENT_VA(this, line); @@ -168,7 +183,7 @@ bool SBLineEntry::GetDescription(SBStream &description) { if (m_opaque_up) { char file_path[PATH_MAX * 2]; - m_opaque_up->file.GetPath(file_path, sizeof(file_path)); + m_opaque_up->GetFile().GetPath(file_path, sizeof(file_path)); strm.Printf("%s:%u", file_path, GetLine()); if (GetColumn() > 0) strm.Printf(":%u", GetColumn()); diff --git a/contrib/llvm-project/lldb/source/API/SBProcess.cpp b/contrib/llvm-project/lldb/source/API/SBProcess.cpp index 4864ea0e7d02..b88f897ff528 100644 --- a/contrib/llvm-project/lldb/source/API/SBProcess.cpp +++ b/contrib/llvm-project/lldb/source/API/SBProcess.cpp @@ -14,6 +14,7 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" +#include "lldb/Core/AddressRangeListImpl.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -26,6 +27,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/Args.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" @@ -38,6 +40,7 @@ #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/API/SBMemoryRegionInfoList.h" +#include "lldb/API/SBSaveCoreOptions.h" #include "lldb/API/SBScriptObject.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStringList.h" @@ -77,7 +80,7 @@ SBProcess::~SBProcess() = default; const char *SBProcess::GetBroadcasterClassName() { LLDB_INSTRUMENT(); - return Process::GetStaticBroadcasterClass().AsCString(); + return ConstString(Process::GetStaticBroadcasterClass()).AsCString(); } const char *SBProcess::GetPluginName() { @@ -320,8 +323,8 @@ void SBProcess::ReportEventState(const SBEvent &event, FileSP out) const { if (process_sp) { StreamFile stream(out); const StateType event_state = SBProcess::GetStateFromEvent(event); - stream.Printf("Process %" PRIu64 " %s\n", - process_sp->GetID(), SBDebugger::StateAsCString(event_state)); + stream.Printf("Process %" PRIu64 " %s\n", process_sp->GetID(), + SBDebugger::StateAsCString(event_state)); } } @@ -378,7 +381,6 @@ bool SBProcess::SetSelectedThreadByIndexID(uint32_t index_id) { ret_val = process_sp->GetThreadList().SetSelectedThreadByIndexID(index_id); } - return ret_val; } @@ -546,7 +548,6 @@ ByteOrder SBProcess::GetByteOrder() const { if (process_sp) byteOrder = process_sp->GetTarget().GetArchitecture().GetByteOrder(); - return byteOrder; } @@ -558,7 +559,6 @@ uint32_t SBProcess::GetAddressByteSize() const { if (process_sp) size = process_sp->GetTarget().GetArchitecture().GetAddressByteSize(); - return size; } @@ -807,7 +807,56 @@ SBBroadcaster SBProcess::GetBroadcaster() const { const char *SBProcess::GetBroadcasterClass() { LLDB_INSTRUMENT(); - return Process::GetStaticBroadcasterClass().AsCString(); + return ConstString(Process::GetStaticBroadcasterClass()).AsCString(); +} + +lldb::SBAddressRangeList SBProcess::FindRangesInMemory( + const void *buf, uint64_t size, const SBAddressRangeList &ranges, + uint32_t alignment, uint32_t max_matches, SBError &error) { + LLDB_INSTRUMENT_VA(this, buf, size, ranges, alignment, max_matches, error); + + lldb::SBAddressRangeList matches; + + ProcessSP process_sp(GetSP()); + if (!process_sp) { + error.SetErrorString("SBProcess is invalid"); + return matches; + } + Process::StopLocker stop_locker; + if (!stop_locker.TryLock(&process_sp->GetRunLock())) { + error.SetErrorString("process is running"); + return matches; + } + std::lock_guard<std::recursive_mutex> guard( + process_sp->GetTarget().GetAPIMutex()); + matches.m_opaque_up->ref() = process_sp->FindRangesInMemory( + reinterpret_cast<const uint8_t *>(buf), size, ranges.ref().ref(), + alignment, max_matches, error.ref()); + return matches; +} + +lldb::addr_t SBProcess::FindInMemory(const void *buf, uint64_t size, + const SBAddressRange &range, + uint32_t alignment, SBError &error) { + LLDB_INSTRUMENT_VA(this, buf, size, range, alignment, error); + + ProcessSP process_sp(GetSP()); + + if (!process_sp) { + error.SetErrorString("SBProcess is invalid"); + return LLDB_INVALID_ADDRESS; + } + + Process::StopLocker stop_locker; + if (!stop_locker.TryLock(&process_sp->GetRunLock())) { + error.SetErrorString("process is running"); + return LLDB_INVALID_ADDRESS; + } + + std::lock_guard<std::recursive_mutex> guard( + process_sp->GetTarget().GetAPIMutex()); + return process_sp->FindInMemory(reinterpret_cast<const uint8_t *>(buf), size, + range.ref(), alignment, error.ref()); } size_t SBProcess::ReadMemory(addr_t addr, void *dst, size_t dst_len, @@ -928,6 +977,14 @@ size_t SBProcess::WriteMemory(addr_t addr, const void *src, size_t src_len, return bytes_written; } +void SBProcess::GetStatus(SBStream &status) { + LLDB_INSTRUMENT_VA(this, status); + + ProcessSP process_sp(GetSP()); + if (process_sp) + process_sp->GetStatus(status.ref()); +} + bool SBProcess::GetDescription(SBStream &description) { LLDB_INSTRUMENT_VA(this, description); @@ -1160,13 +1217,28 @@ bool SBProcess::IsInstrumentationRuntimePresent( lldb::SBError SBProcess::SaveCore(const char *file_name) { LLDB_INSTRUMENT_VA(this, file_name); - return SaveCore(file_name, "", SaveCoreStyle::eSaveCoreFull); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(SaveCoreStyle::eSaveCoreFull); + return SaveCore(options); } lldb::SBError SBProcess::SaveCore(const char *file_name, const char *flavor, SaveCoreStyle core_style) { LLDB_INSTRUMENT_VA(this, file_name, flavor, core_style); + SBSaveCoreOptions options; + options.SetOutputFile(SBFileSpec(file_name)); + options.SetStyle(core_style); + SBError error = options.SetPluginName(flavor); + if (error.Fail()) + return error; + return SaveCore(options); +} + +lldb::SBError SBProcess::SaveCore(SBSaveCoreOptions &options) { + + LLDB_INSTRUMENT_VA(this, options); lldb::SBError error; ProcessSP process_sp(GetSP()); @@ -1183,10 +1255,7 @@ lldb::SBError SBProcess::SaveCore(const char *file_name, return error; } - FileSpec core_file(file_name); - FileSystem::Instance().Resolve(core_file); - error.ref() = PluginManager::SaveCore(process_sp, core_file, core_style, - flavor); + error.ref() = PluginManager::SaveCore(process_sp, options.ref()); return error; } @@ -1244,6 +1313,109 @@ lldb::SBProcessInfo SBProcess::GetProcessInfo() { return sb_proc_info; } +lldb::SBFileSpec SBProcess::GetCoreFile() { + LLDB_INSTRUMENT_VA(this); + + ProcessSP process_sp(GetSP()); + FileSpec core_file; + if (process_sp) { + core_file = process_sp->GetCoreFile(); + } + return SBFileSpec(core_file); +} + +addr_t SBProcess::GetAddressMask(AddressMaskType type, + AddressMaskRange addr_range) { + LLDB_INSTRUMENT_VA(this, type, addr_range); + + if (ProcessSP process_sp = GetSP()) { + switch (type) { + case eAddressMaskTypeCode: + if (addr_range == eAddressMaskRangeHigh) + return process_sp->GetHighmemCodeAddressMask(); + else + return process_sp->GetCodeAddressMask(); + case eAddressMaskTypeData: + if (addr_range == eAddressMaskRangeHigh) + return process_sp->GetHighmemDataAddressMask(); + else + return process_sp->GetDataAddressMask(); + case eAddressMaskTypeAny: + if (addr_range == eAddressMaskRangeHigh) + return process_sp->GetHighmemDataAddressMask(); + else + return process_sp->GetDataAddressMask(); + } + } + return LLDB_INVALID_ADDRESS_MASK; +} + +void SBProcess::SetAddressMask(AddressMaskType type, addr_t mask, + AddressMaskRange addr_range) { + LLDB_INSTRUMENT_VA(this, type, mask, addr_range); + + if (ProcessSP process_sp = GetSP()) { + switch (type) { + case eAddressMaskTypeCode: + if (addr_range == eAddressMaskRangeAll) { + process_sp->SetCodeAddressMask(mask); + process_sp->SetHighmemCodeAddressMask(mask); + } else if (addr_range == eAddressMaskRangeHigh) { + process_sp->SetHighmemCodeAddressMask(mask); + } else { + process_sp->SetCodeAddressMask(mask); + } + break; + case eAddressMaskTypeData: + if (addr_range == eAddressMaskRangeAll) { + process_sp->SetDataAddressMask(mask); + process_sp->SetHighmemDataAddressMask(mask); + } else if (addr_range == eAddressMaskRangeHigh) { + process_sp->SetHighmemDataAddressMask(mask); + } else { + process_sp->SetDataAddressMask(mask); + } + break; + case eAddressMaskTypeAll: + if (addr_range == eAddressMaskRangeAll) { + process_sp->SetCodeAddressMask(mask); + process_sp->SetDataAddressMask(mask); + process_sp->SetHighmemCodeAddressMask(mask); + process_sp->SetHighmemDataAddressMask(mask); + } else if (addr_range == eAddressMaskRangeHigh) { + process_sp->SetHighmemCodeAddressMask(mask); + process_sp->SetHighmemDataAddressMask(mask); + } else { + process_sp->SetCodeAddressMask(mask); + process_sp->SetDataAddressMask(mask); + } + break; + } + } +} + +void SBProcess::SetAddressableBits(AddressMaskType type, uint32_t num_bits, + AddressMaskRange addr_range) { + LLDB_INSTRUMENT_VA(this, type, num_bits, addr_range); + + SetAddressMask(type, AddressableBits::AddressableBitToMask(num_bits), + addr_range); +} + +addr_t SBProcess::FixAddress(addr_t addr, AddressMaskType type) { + LLDB_INSTRUMENT_VA(this, addr, type); + + if (ProcessSP process_sp = GetSP()) { + if (type == eAddressMaskTypeAny) + return process_sp->FixAnyAddress(addr); + else if (type == eAddressMaskTypeData) + return process_sp->FixDataAddress(addr); + else if (type == eAddressMaskTypeCode) + return process_sp->FixCodeAddress(addr); + } + return addr; +} + lldb::addr_t SBProcess::AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &sb_error) { LLDB_INSTRUMENT_VA(this, size, permissions, sb_error); diff --git a/contrib/llvm-project/lldb/source/API/SBSaveCoreOptions.cpp b/contrib/llvm-project/lldb/source/API/SBSaveCoreOptions.cpp new file mode 100644 index 000000000000..6c3f74596203 --- /dev/null +++ b/contrib/llvm-project/lldb/source/API/SBSaveCoreOptions.cpp @@ -0,0 +1,85 @@ +//===-- SBSaveCoreOptions.cpp -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBSaveCoreOptions.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBFileSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Utility/Instrumentation.h" + +#include "Utils.h" + +using namespace lldb; + +SBSaveCoreOptions::SBSaveCoreOptions() { + LLDB_INSTRUMENT_VA(this) + + m_opaque_up = std::make_unique<lldb_private::SaveCoreOptions>(); +} + +SBSaveCoreOptions::SBSaveCoreOptions(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +const SBSaveCoreOptions & +SBSaveCoreOptions::operator=(const SBSaveCoreOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +SBError SBSaveCoreOptions::SetPluginName(const char *name) { + LLDB_INSTRUMENT_VA(this, name); + lldb_private::Status error = m_opaque_up->SetPluginName(name); + return SBError(error); +} + +void SBSaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { + LLDB_INSTRUMENT_VA(this, style); + m_opaque_up->SetStyle(style); +} + +void SBSaveCoreOptions::SetOutputFile(lldb::SBFileSpec file_spec) { + LLDB_INSTRUMENT_VA(this, file_spec); + m_opaque_up->SetOutputFile(file_spec.ref()); +} + +const char *SBSaveCoreOptions::GetPluginName() const { + LLDB_INSTRUMENT_VA(this); + const auto name = m_opaque_up->GetPluginName(); + if (!name) + return nullptr; + return lldb_private::ConstString(name.value()).GetCString(); +} + +SBFileSpec SBSaveCoreOptions::GetOutputFile() const { + LLDB_INSTRUMENT_VA(this); + const auto file_spec = m_opaque_up->GetOutputFile(); + if (file_spec) + return SBFileSpec(file_spec.value()); + return SBFileSpec(); +} + +lldb::SaveCoreStyle SBSaveCoreOptions::GetStyle() const { + LLDB_INSTRUMENT_VA(this); + return m_opaque_up->GetStyle(); +} + +void SBSaveCoreOptions::Clear() { + LLDB_INSTRUMENT_VA(this); + m_opaque_up->Clear(); +} + +lldb_private::SaveCoreOptions &SBSaveCoreOptions::ref() const { + return *m_opaque_up.get(); +} diff --git a/contrib/llvm-project/lldb/source/API/SBStatisticsOptions.cpp b/contrib/llvm-project/lldb/source/API/SBStatisticsOptions.cpp new file mode 100644 index 000000000000..71d4048573b5 --- /dev/null +++ b/contrib/llvm-project/lldb/source/API/SBStatisticsOptions.cpp @@ -0,0 +1,82 @@ +//===-- SBStatisticsOptions.cpp -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBStatisticsOptions.h" +#include "lldb/Target/Statistics.h" +#include "lldb/Utility/Instrumentation.h" + +#include "Utils.h" + +using namespace lldb; +using namespace lldb_private; + +SBStatisticsOptions::SBStatisticsOptions() + : m_opaque_up(new StatisticsOptions()) { + LLDB_INSTRUMENT_VA(this); +} + +SBStatisticsOptions::SBStatisticsOptions(const SBStatisticsOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBStatisticsOptions::~SBStatisticsOptions() = default; + +const SBStatisticsOptions & +SBStatisticsOptions::operator=(const SBStatisticsOptions &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +void SBStatisticsOptions::SetSummaryOnly(bool b) { + m_opaque_up->SetSummaryOnly(b); +} + +bool SBStatisticsOptions::GetSummaryOnly() { + return m_opaque_up->GetSummaryOnly(); +} + +void SBStatisticsOptions::SetIncludeTargets(bool b) { + m_opaque_up->SetIncludeTargets(b); +} + +bool SBStatisticsOptions::GetIncludeTargets() const { + return m_opaque_up->GetIncludeTargets(); +} + +void SBStatisticsOptions::SetIncludeModules(bool b) { + m_opaque_up->SetIncludeModules(b); +} + +bool SBStatisticsOptions::GetIncludeModules() const { + return m_opaque_up->GetIncludeModules(); +} + +void SBStatisticsOptions::SetIncludeTranscript(bool b) { + m_opaque_up->SetIncludeTranscript(b); +} + +bool SBStatisticsOptions::GetIncludeTranscript() const { + return m_opaque_up->GetIncludeTranscript(); +} + +void SBStatisticsOptions::SetReportAllAvailableDebugInfo(bool b) { + m_opaque_up->SetLoadAllDebugInfo(b); +} + +bool SBStatisticsOptions::GetReportAllAvailableDebugInfo() { + return m_opaque_up->GetLoadAllDebugInfo(); +} + +const lldb_private::StatisticsOptions &SBStatisticsOptions::ref() const { + return *m_opaque_up; +} diff --git a/contrib/llvm-project/lldb/source/API/SBTarget.cpp b/contrib/llvm-project/lldb/source/API/SBTarget.cpp index 8e616afbcb4e..2c336296f0b8 100644 --- a/contrib/llvm-project/lldb/source/API/SBTarget.cpp +++ b/contrib/llvm-project/lldb/source/API/SBTarget.cpp @@ -147,7 +147,7 @@ SBModule SBTarget::GetModuleAtIndexFromEvent(const uint32_t idx, const char *SBTarget::GetBroadcasterClassName() { LLDB_INSTRUMENT(); - return Target::GetStaticBroadcasterClass().AsCString(); + return ConstString(Target::GetStaticBroadcasterClass()).AsCString(); } bool SBTarget::IsValid() const { @@ -199,15 +199,22 @@ SBDebugger SBTarget::GetDebugger() const { SBStructuredData SBTarget::GetStatistics() { LLDB_INSTRUMENT_VA(this); + SBStatisticsOptions options; + return GetStatistics(options); +} + +SBStructuredData SBTarget::GetStatistics(SBStatisticsOptions options) { + LLDB_INSTRUMENT_VA(this); SBStructuredData data; TargetSP target_sp(GetSP()); if (!target_sp) return data; std::string json_str = - llvm::formatv("{0:2}", - DebuggerStats::ReportStatistics(target_sp->GetDebugger(), - target_sp.get())).str(); + llvm::formatv("{0:2}", DebuggerStats::ReportStatistics( + target_sp->GetDebugger(), target_sp.get(), + options.ref())) + .str(); data.m_impl_up->SetObjectSP(StructuredData::ParseJSON(json_str)); return data; } @@ -1140,7 +1147,7 @@ void SBTarget::GetBreakpointNames(SBStringList &names) { std::vector<std::string> name_vec; target_sp->GetBreakpointNames(name_vec); - for (auto name : name_vec) + for (const auto &name : name_vec) names.AppendString(name.c_str()); } } @@ -1782,6 +1789,11 @@ lldb::SBSymbolContextList SBTarget::FindGlobalFunctions(const char *name, target_sp->GetImages().FindFunctions(RegularExpression(name_ref), function_options, *sb_sc_list); break; + case eMatchTypeRegexInsensitive: + target_sp->GetImages().FindFunctions( + RegularExpression(name_ref, llvm::Regex::RegexFlags::IgnoreCase), + function_options, *sb_sc_list); + break; case eMatchTypeStartsWith: regexstr = llvm::Regex::escape(name) + ".*"; target_sp->GetImages().FindFunctions(RegularExpression(regexstr), @@ -1929,6 +1941,11 @@ SBValueList SBTarget::FindGlobalVariables(const char *name, target_sp->GetImages().FindGlobalVariables(RegularExpression(name_ref), max_matches, variable_list); break; + case eMatchTypeRegexInsensitive: + target_sp->GetImages().FindGlobalVariables( + RegularExpression(name_ref, llvm::Regex::IgnoreCase), max_matches, + variable_list); + break; case eMatchTypeStartsWith: regexstr = "^" + llvm::Regex::escape(name) + ".*"; target_sp->GetImages().FindGlobalVariables(RegularExpression(regexstr), @@ -2004,6 +2021,30 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr, return sb_instructions; } +lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress start_addr, + lldb::SBAddress end_addr, + const char *flavor_string) { + LLDB_INSTRUMENT_VA(this, start_addr, end_addr, flavor_string); + + SBInstructionList sb_instructions; + + TargetSP target_sp(GetSP()); + if (target_sp) { + lldb::addr_t start_load_addr = start_addr.GetLoadAddress(*this); + lldb::addr_t end_load_addr = end_addr.GetLoadAddress(*this); + if (end_load_addr > start_load_addr) { + lldb::addr_t size = end_load_addr - start_load_addr; + + AddressRange range(start_load_addr, size); + const bool force_live_memory = true; + sb_instructions.SetDisassembler(Disassembler::DisassembleRange( + target_sp->GetArchitecture(), nullptr, flavor_string, *target_sp, + range, force_live_memory)); + } + } + return sb_instructions; +} + lldb::SBInstructionList SBTarget::GetInstructions(lldb::SBAddress base_addr, const void *buf, size_t size) { diff --git a/contrib/llvm-project/lldb/source/API/SBThread.cpp b/contrib/llvm-project/lldb/source/API/SBThread.cpp index fa4c80e59d97..53643362421d 100644 --- a/contrib/llvm-project/lldb/source/API/SBThread.cpp +++ b/contrib/llvm-project/lldb/source/API/SBThread.cpp @@ -53,7 +53,7 @@ using namespace lldb_private; const char *SBThread::GetBroadcasterClassName() { LLDB_INSTRUMENT(); - return Thread::GetStaticBroadcasterClass().AsCString(); + return ConstString(Thread::GetStaticBroadcasterClass()).AsCString(); } // Constructors @@ -722,7 +722,7 @@ void SBThread::StepInstruction(bool step_over, SBError &error) { Thread *thread = exe_ctx.GetThreadPtr(); Status new_plan_status; ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction( - step_over, true, true, new_plan_status)); + step_over, false, true, new_plan_status)); if (new_plan_status.Success()) error = ResumeNewPlan(exe_ctx, new_plan_sp.get()); @@ -819,7 +819,7 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, step_file_spec = sb_file_spec.ref(); } else { if (frame_sc.line_entry.IsValid()) - step_file_spec = frame_sc.line_entry.file; + step_file_spec = frame_sc.line_entry.GetFile(); else { sb_error.SetErrorString("invalid file argument or no file for frame"); return sb_error; diff --git a/contrib/llvm-project/lldb/source/API/SBType.cpp b/contrib/llvm-project/lldb/source/API/SBType.cpp index ac0e56303fae..8a063e5ad61d 100644 --- a/contrib/llvm-project/lldb/source/API/SBType.cpp +++ b/contrib/llvm-project/lldb/source/API/SBType.cpp @@ -7,19 +7,25 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBType.h" +#include "Utils.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBModule.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBTypeEnumMember.h" #include "lldb/Core/Mangled.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Instrumentation.h" +#include "lldb/Utility/Scalar.h" #include "lldb/Utility/Stream.h" #include "llvm/ADT/APSInt.h" +#include "llvm/Support/MathExtras.h" #include <memory> #include <optional> @@ -127,6 +133,18 @@ uint64_t SBType::GetByteSize() { return 0; } +uint64_t SBType::GetByteAlign() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return 0; + + std::optional<uint64_t> bit_align = + m_opaque_sp->GetCompilerType(/*prefer_dynamic=*/false) + .GetTypeBitAlign(nullptr); + return llvm::divideCeil(bit_align.value_or(0), 8); +} + bool SBType::IsPointerType() { LLDB_INSTRUMENT_VA(this); @@ -325,6 +343,79 @@ lldb::SBTypeMemberFunction SBType::GetMemberFunctionAtIndex(uint32_t idx) { return sb_func_type; } +SBTypeStaticField::SBTypeStaticField() { LLDB_INSTRUMENT_VA(this); } + +SBTypeStaticField::SBTypeStaticField(lldb_private::CompilerDecl decl) + : m_opaque_up(decl ? std::make_unique<CompilerDecl>(decl) : nullptr) {} + +SBTypeStaticField::SBTypeStaticField(const SBTypeStaticField &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBTypeStaticField &SBTypeStaticField::operator=(const SBTypeStaticField &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +SBTypeStaticField::~SBTypeStaticField() { LLDB_INSTRUMENT_VA(this); } + +SBTypeStaticField::operator bool() const { + LLDB_INSTRUMENT_VA(this); + + return IsValid(); +} + +bool SBTypeStaticField::IsValid() const { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up != nullptr; +} + +const char *SBTypeStaticField::GetName() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return ""; + return m_opaque_up->GetName().GetCString(); +} + +const char *SBTypeStaticField::GetMangledName() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return ""; + return m_opaque_up->GetMangledName().GetCString(); +} + +SBType SBTypeStaticField::GetType() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return SBType(); + return SBType(m_opaque_up->GetType()); +} + +SBValue SBTypeStaticField::GetConstantValue(lldb::SBTarget target) { + LLDB_INSTRUMENT_VA(this, target); + + if (!IsValid()) + return SBValue(); + + Scalar value = m_opaque_up->GetConstantValue(); + if (!value.IsValid()) + return SBValue(); + DataExtractor data; + value.GetData(data); + auto value_obj_sp = ValueObjectConstResult::Create( + target.GetSP().get(), m_opaque_up->GetType(), m_opaque_up->GetName(), + data); + return SBValue(std::move(value_obj_sp)); +} + lldb::SBType SBType::GetUnqualifiedType() { LLDB_INSTRUMENT_VA(this); @@ -438,6 +529,16 @@ SBTypeMember SBType::GetVirtualBaseClassAtIndex(uint32_t idx) { return sb_type_member; } +SBTypeStaticField SBType::GetStaticFieldWithName(const char *name) { + LLDB_INSTRUMENT_VA(this, name); + + if (!IsValid() || !name) + return SBTypeStaticField(); + + return SBTypeStaticField(m_opaque_sp->GetCompilerType(/*prefer_dynamic=*/true) + .GetStaticFieldWithName(name)); +} + SBTypeEnumMemberList SBType::GetEnumMembers() { LLDB_INSTRUMENT_VA(this); diff --git a/contrib/llvm-project/lldb/source/API/SBValue.cpp b/contrib/llvm-project/lldb/source/API/SBValue.cpp index 89d26a1fbe28..96670481eca3 100644 --- a/contrib/llvm-project/lldb/source/API/SBValue.cpp +++ b/contrib/llvm-project/lldb/source/API/SBValue.cpp @@ -379,7 +379,10 @@ const char *SBValue::GetObjectDescription() { if (!value_sp) return nullptr; - return ConstString(value_sp->GetObjectDescription()).GetCString(); + llvm::Expected<std::string> str = value_sp->GetObjectDescription(); + if (!str) + return ConstString("error: " + toString(str.takeError())).AsCString(); + return ConstString(*str).AsCString(); } SBType SBValue::GetType() { @@ -761,6 +764,21 @@ lldb::SBValue SBValue::GetNonSyntheticValue() { return value_sb; } +lldb::SBValue SBValue::GetSyntheticValue() { + LLDB_INSTRUMENT_VA(this); + + SBValue value_sb; + if (IsValid()) { + ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(), + m_opaque_sp->GetUseDynamic(), true)); + value_sb.SetSP(proxy_sp); + if (!value_sb.IsSynthetic()) { + return {}; + } + } + return value_sb; +} + lldb::DynamicValueType SBValue::GetPreferDynamicValue() { LLDB_INSTRUMENT_VA(this); @@ -909,6 +927,25 @@ uint64_t SBValue::GetValueAsUnsigned(uint64_t fail_value) { return fail_value; } +lldb::addr_t SBValue::GetValueAsAddress() { + addr_t fail_value = LLDB_INVALID_ADDRESS; + ValueLocker locker; + lldb::ValueObjectSP value_sp(GetSP(locker)); + if (value_sp) { + bool success = true; + uint64_t ret_val = fail_value; + ret_val = value_sp->GetValueAsUnsigned(fail_value, &success); + if (!success) + return fail_value; + ProcessSP process_sp = m_opaque_sp->GetProcessSP(); + if (!process_sp) + return ret_val; + return process_sp->FixDataAddress(ret_val); + } + + return fail_value; +} + bool SBValue::MightHaveChildren() { LLDB_INSTRUMENT_VA(this); @@ -947,7 +984,7 @@ uint32_t SBValue::GetNumChildren(uint32_t max) { ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); if (value_sp) - num_children = value_sp->GetNumChildren(max); + num_children = value_sp->GetNumChildrenIgnoringErrors(max); return num_children; } @@ -1214,7 +1251,10 @@ bool SBValue::GetDescription(SBStream &description) { DumpValueObjectOptions options; options.SetUseDynamicType(m_opaque_sp->GetUseDynamic()); options.SetUseSyntheticValue(m_opaque_sp->GetUseSynthetic()); - value_sp->Dump(strm, options); + if (llvm::Error error = value_sp->Dump(strm, options)) { + strm << "error: " << toString(std::move(error)); + return false; + } } else { strm.PutCString("No value"); } @@ -1262,26 +1302,8 @@ lldb::addr_t SBValue::GetLoadAddress() { lldb::addr_t value = LLDB_INVALID_ADDRESS; ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); - if (value_sp) { - TargetSP target_sp(value_sp->GetTargetSP()); - if (target_sp) { - const bool scalar_is_load_address = true; - AddressType addr_type; - value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type); - if (addr_type == eAddressTypeFile) { - ModuleSP module_sp(value_sp->GetModule()); - if (!module_sp) - value = LLDB_INVALID_ADDRESS; - else { - Address addr; - module_sp->ResolveFileAddress(value, addr); - value = addr.GetLoadAddress(target_sp.get()); - } - } else if (addr_type == eAddressTypeHost || - addr_type == eAddressTypeInvalid) - value = LLDB_INVALID_ADDRESS; - } - } + if (value_sp) + return value_sp->GetLoadAddress(); return value; } diff --git a/contrib/llvm-project/lldb/source/API/SystemInitializerFull.cpp b/contrib/llvm-project/lldb/source/API/SystemInitializerFull.cpp index c48466f25ede..995d14f7c1fa 100644 --- a/contrib/llvm-project/lldb/source/API/SystemInitializerFull.cpp +++ b/contrib/llvm-project/lldb/source/API/SystemInitializerFull.cpp @@ -10,6 +10,7 @@ #include "lldb/API/SBCommandInterpreter.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Host/Config.h" #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" @@ -57,6 +58,7 @@ llvm::Error SystemInitializerFull::Initialize() { llvm::InitializeAllAsmPrinters(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllDisassemblers(); + // Initialize the command line parser in LLVM. This usually isn't necessary // as we aren't dealing with command line options here, but otherwise some // other code in Clang/LLVM might be tempted to call this function from a @@ -65,10 +67,13 @@ llvm::Error SystemInitializerFull::Initialize() { const char *arg0 = "lldb"; llvm::cl::ParseCommandLineOptions(1, &arg0); + // Initialize the progress manager. + ProgressManager::Initialize(); + #define LLDB_PLUGIN(p) LLDB_PLUGIN_INITIALIZE(p); #include "Plugins/Plugins.def" - // Scan for any system or user LLDB plug-ins + // Scan for any system or user LLDB plug-ins. PluginManager::Initialize(); // The process settings need to know about installed plug-ins, so the @@ -84,15 +89,18 @@ llvm::Error SystemInitializerFull::Initialize() { void SystemInitializerFull::Terminate() { Debugger::SettingsTerminate(); - // Terminate plug-ins in core LLDB + // Terminate plug-ins in core LLDB. ProcessTrace::Terminate(); - // Terminate and unload and loaded system or user LLDB plug-ins + // Terminate and unload and loaded system or user LLDB plug-ins. PluginManager::Terminate(); #define LLDB_PLUGIN(p) LLDB_PLUGIN_TERMINATE(p); #include "Plugins/Plugins.def" + // Terminate the progress manager. + ProgressManager::Terminate(); + // Now shutdown the common parts, in reverse order. SystemInitializerCommon::Terminate(); } diff --git a/contrib/llvm-project/lldb/source/Breakpoint/Breakpoint.cpp b/contrib/llvm-project/lldb/source/Breakpoint/Breakpoint.cpp index af5dcc9cd88d..dc80d435ad44 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/Breakpoint.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/Breakpoint.cpp @@ -44,17 +44,14 @@ const char *Breakpoint::g_option_names[static_cast<uint32_t>( Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware, bool resolve_indirect_symbols) - : m_being_created(true), m_hardware(hardware), m_target(target), - m_filter_sp(filter_sp), m_resolver_sp(resolver_sp), m_options(true), - m_locations(*this), m_resolve_indirect_symbols(resolve_indirect_symbols), - m_hit_counter() { - m_being_created = false; -} + : m_hardware(hardware), m_target(target), m_filter_sp(filter_sp), + m_resolver_sp(resolver_sp), m_options(true), m_locations(*this), + m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_counter() {} Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp) - : m_being_created(true), m_hardware(source_bp.m_hardware), - m_target(new_target), m_name_list(source_bp.m_name_list), - m_options(source_bp.m_options), m_locations(*this), + : m_hardware(source_bp.m_hardware), m_target(new_target), + m_name_list(source_bp.m_name_list), m_options(source_bp.m_options), + m_locations(*this), m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols), m_hit_counter() {} @@ -888,7 +885,7 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level, s->Printf("Names:"); s->EOL(); s->IndentMore(); - for (std::string name : m_name_list) { + for (const std::string &name : m_name_list) { s->Indent(); s->Printf("%s\n", name.c_str()); } @@ -979,9 +976,8 @@ bool Breakpoint::EvaluatePrecondition(StoppointCallbackContext &context) { void Breakpoint::SendBreakpointChangedEvent( lldb::BreakpointEventType eventKind) { - if (!m_being_created && !IsInternal() && - GetTarget().EventTypeHasListeners( - Target::eBroadcastBitBreakpointChanged)) { + if (!IsInternal() && GetTarget().EventTypeHasListeners( + Target::eBroadcastBitBreakpointChanged)) { std::shared_ptr<BreakpointEventData> data = std::make_shared<BreakpointEventData>(eventKind, shared_from_this()); @@ -994,7 +990,7 @@ void Breakpoint::SendBreakpointChangedEvent( if (!breakpoint_data_sp) return; - if (!m_being_created && !IsInternal() && + if (!IsInternal() && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, breakpoint_data_sp); diff --git a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointIDList.cpp b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointIDList.cpp index 5ab2c9a8dc38..5fc9f95a75db 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -15,6 +15,9 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/StreamString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" + using namespace lldb; using namespace lldb_private; @@ -48,27 +51,8 @@ bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) { // return true. } -bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id, - size_t *position) const { - for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) { - BreakpointID tmp_id = m_breakpoint_ids[i]; - if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() && - tmp_id.GetLocationID() == bp_id.GetLocationID()) { - *position = i; - return true; - } - } - - return false; -} - -bool BreakpointIDList::FindBreakpointID(const char *bp_id_str, - size_t *position) const { - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (!bp_id) - return false; - - return FindBreakpointID(*bp_id, position); +bool BreakpointIDList::Contains(BreakpointID bp_id) const { + return llvm::is_contained(m_breakpoint_ids, bp_id); } // This function takes OLD_ARGS, which is usually the result of breaking the @@ -128,32 +112,27 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( } else { // See if user has specified id.* llvm::StringRef tmp_str = old_args[i].ref(); - size_t pos = tmp_str.find('.'); - if (pos != llvm::StringRef::npos) { - llvm::StringRef bp_id_str = tmp_str.substr(0, pos); - if (BreakpointID::IsValidIDExpression(bp_id_str) && - tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) { - - BreakpointSP breakpoint_sp; - auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str); - if (bp_id) - breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); - if (!breakpoint_sp) { - new_args.Clear(); - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "'%d' is not a valid breakpoint ID.\n", - bp_id->GetBreakpointID()); - } - const size_t num_locations = breakpoint_sp->GetNumLocations(); - for (size_t j = 0; j < num_locations; ++j) { - BreakpointLocation *bp_loc = - breakpoint_sp->GetLocationAtIndex(j).get(); - StreamString canonical_id_str; - BreakpointID::GetCanonicalReference( - &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); - new_args.AppendArgument(canonical_id_str.GetString()); - } + auto [prefix, suffix] = tmp_str.split('.'); + if (suffix == "*" && BreakpointID::IsValidIDExpression(prefix)) { + + BreakpointSP breakpoint_sp; + auto bp_id = BreakpointID::ParseCanonicalReference(prefix); + if (bp_id) + breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID()); + if (!breakpoint_sp) { + new_args.Clear(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "'%d' is not a valid breakpoint ID.\n", + bp_id->GetBreakpointID()); + } + const size_t num_locations = breakpoint_sp->GetNumLocations(); + for (size_t j = 0; j < num_locations; ++j) { + BreakpointLocation *bp_loc = + breakpoint_sp->GetLocationAtIndex(j).get(); + StreamString canonical_id_str; + BreakpointID::GetCanonicalReference( + &canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID()); + new_args.AppendArgument(canonical_id_str.GetString()); } } } @@ -280,7 +259,7 @@ llvm::Error BreakpointIDList::FindAndReplaceIDRanges( if (!names_found.empty()) { for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) { - for (std::string name : names_found) { + for (const std::string &name : names_found) { if (bkpt_sp->MatchesName(name.c_str())) { StreamString canonical_id_str; BreakpointID::GetCanonicalReference( diff --git a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocation.cpp b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocation.cpp index 98de059c2e29..41911fad41c6 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -32,9 +32,9 @@ using namespace lldb_private; BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner, const Address &addr, lldb::tid_t tid, bool hardware, bool check_for_resolver) - : m_being_created(true), m_should_resolve_indirect_functions(false), - m_is_reexported(false), m_is_indirect(false), m_address(addr), - m_owner(owner), m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() { + : m_should_resolve_indirect_functions(false), m_is_reexported(false), + m_is_indirect(false), m_address(addr), m_owner(owner), + m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() { if (check_for_resolver) { Symbol *symbol = m_address.CalculateSymbolContextSymbol(); if (symbol && symbol->IsIndirect()) { @@ -42,8 +42,7 @@ BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner, } } - SetThreadID(tid); - m_being_created = false; + SetThreadIDInternal(tid); } BreakpointLocation::~BreakpointLocation() { ClearBreakpointSite(); } @@ -100,14 +99,7 @@ void BreakpointLocation::SetAutoContinue(bool auto_continue) { } void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) { - if (thread_id != LLDB_INVALID_THREAD_ID) - GetLocationOptions().SetThreadID(thread_id); - else { - // If we're resetting this to an invalid thread id, then don't make an - // options pointer just to do that. - if (m_options_up != nullptr) - m_options_up->SetThreadID(thread_id); - } + SetThreadIDInternal(thread_id); SendBreakpointLocationChangedEvent(eBreakpointEventTypeThreadChanged); } @@ -515,7 +507,7 @@ void BreakpointLocation::GetDescription(Stream *s, else s->PutCString("where = "); sc.DumpStopContext(s, m_owner.GetTarget().GetProcessSP().get(), m_address, - false, true, false, true, true); + false, true, false, true, true, true); } else { if (sc.module_sp) { s->EOL(); @@ -532,6 +524,12 @@ void BreakpointLocation::GetDescription(Stream *s, s->EOL(); s->Indent("function = "); s->PutCString(sc.function->GetName().AsCString("<unknown>")); + if (ConstString mangled_name = + sc.function->GetMangled().GetMangledName()) { + s->EOL(); + s->Indent("mangled function = "); + s->PutCString(mangled_name.AsCString()); + } } if (sc.line_entry.line > 0) { @@ -646,9 +644,8 @@ void BreakpointLocation::Dump(Stream *s) const { void BreakpointLocation::SendBreakpointLocationChangedEvent( lldb::BreakpointEventType eventKind) { - if (!m_being_created && !m_owner.IsInternal() && - m_owner.GetTarget().EventTypeHasListeners( - Target::eBroadcastBitBreakpointChanged)) { + if (!m_owner.IsInternal() && m_owner.GetTarget().EventTypeHasListeners( + Target::eBroadcastBitBreakpointChanged)) { auto data_sp = std::make_shared<Breakpoint::BreakpointEventData>( eventKind, m_owner.shared_from_this()); data_sp->GetBreakpointLocationCollection().Add(shared_from_this()); @@ -665,3 +662,14 @@ void BreakpointLocation::SwapLocation(BreakpointLocationSP swap_from) { m_is_indirect = swap_from->m_is_indirect; m_user_expression_sp.reset(); } + +void BreakpointLocation::SetThreadIDInternal(lldb::tid_t thread_id) { + if (thread_id != LLDB_INVALID_THREAD_ID) + GetLocationOptions().SetThreadID(thread_id); + else { + // If we're resetting this to an invalid thread id, then don't make an + // options pointer just to do that. + if (m_options_up != nullptr) + m_options_up->SetThreadID(thread_id); + } +} diff --git a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointOptions.cpp b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointOptions.cpp index 6c6037dd9edd..1db840169811 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -102,19 +102,11 @@ const char *BreakpointOptions::g_option_names[( "ConditionText", "IgnoreCount", "EnabledState", "OneShotState", "AutoContinue"}; -bool BreakpointOptions::NullCallback(void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) { - return true; -} - // BreakpointOptions constructor BreakpointOptions::BreakpointOptions(bool all_flags_set) - : m_callback(BreakpointOptions::NullCallback), - m_baton_is_command_baton(false), m_callback_is_synchronous(false), - m_enabled(true), m_one_shot(false), m_ignore_count(0), - m_condition_text_hash(0), m_inject_condition(false), + : m_callback(nullptr), m_baton_is_command_baton(false), + m_callback_is_synchronous(false), m_enabled(true), m_one_shot(false), + m_ignore_count(0), m_condition_text_hash(0), m_inject_condition(false), m_auto_continue(false), m_set_flags(0) { if (all_flags_set) m_set_flags.Set(~((Flags::ValueType)0)); @@ -420,7 +412,7 @@ void BreakpointOptions::SetCallback( } void BreakpointOptions::ClearCallback() { - m_callback = BreakpointOptions::NullCallback; + m_callback = nullptr; m_callback_is_synchronous = false; m_callback_baton_sp.reset(); m_baton_is_command_baton = false; @@ -449,7 +441,7 @@ bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context, } bool BreakpointOptions::HasCallback() const { - return m_callback != BreakpointOptions::NullCallback; + return static_cast<bool>(m_callback); } bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) { diff --git a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp index bc6348716ef4..2d52cbf827ef 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -23,6 +23,7 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" @@ -203,8 +204,15 @@ void BreakpointResolver::SetSCMatchesByLine( SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue, llvm::StringRef log_ident, uint32_t line, std::optional<uint16_t> column) { llvm::SmallVector<SymbolContext, 16> all_scs; - for (uint32_t i = 0; i < sc_list.GetSize(); ++i) - all_scs.push_back(sc_list[i]); + + for (const auto &sc : sc_list) { + if (Language::GetGlobalLanguageProperties() + .GetEnableFilterForLineBreakpoints()) + if (Language *lang = Language::FindPlugin(sc.GetLanguage()); + lang && lang->IgnoreForLineBreakpoints(sc)) + continue; + all_scs.push_back(sc); + } while (all_scs.size()) { uint32_t closest_line = UINT32_MAX; @@ -213,9 +221,10 @@ void BreakpointResolver::SetSCMatchesByLine( auto &match = all_scs[0]; auto worklist_begin = std::partition( all_scs.begin(), all_scs.end(), [&](const SymbolContext &sc) { - if (sc.line_entry.file == match.line_entry.file || - *sc.line_entry.original_file_sp == - *match.line_entry.original_file_sp) { + if (sc.line_entry.GetFile() == match.line_entry.GetFile() || + sc.line_entry.original_file_sp->Equal( + *match.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet)) { // When a match is found, keep track of the smallest line number. closest_line = std::min(closest_line, sc.line_entry.line); return false; diff --git a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp index cc4e1d26724f..16c4ee1b88d1 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp @@ -147,8 +147,9 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) { else continue; - if (file != sc.line_entry.file) { - LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file); + if (file != sc.line_entry.GetFile()) { + LLDB_LOG(log, "unexpected symbol context file {0}", + sc.line_entry.GetFile()); continue; } @@ -197,16 +198,16 @@ void BreakpointResolverFileLine::DeduceSourceMapping( return; Log *log = GetLog(LLDBLog::Breakpoints); - const llvm::StringRef path_separator = llvm::sys::path::get_separator( - m_location_spec.GetFileSpec().GetPathStyle()); // Check if "b" is a suffix of "a". // And return std::nullopt if not or the new path // of "a" after consuming "b" from the back. auto check_suffix = - [path_separator](llvm::StringRef a, llvm::StringRef b, - bool case_sensitive) -> std::optional<llvm::StringRef> { + [](llvm::StringRef a, llvm::StringRef b, + bool case_sensitive) -> std::optional<llvm::StringRef> { if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b)) { - if (a.empty() || a.ends_with(path_separator)) { + // Note sc_file_dir and request_file_dir below are normalized + // and always contain the path separator '/'. + if (a.empty() || a.ends_with("/")) { return a; } } @@ -223,7 +224,7 @@ void BreakpointResolverFileLine::DeduceSourceMapping( const bool case_sensitive = request_file.IsCaseSensitive(); for (const SymbolContext &sc : sc_list) { - FileSpec sc_file = sc.line_entry.file; + FileSpec sc_file = sc.line_entry.GetFile(); if (FileSpec::Equal(sc_file, request_file, /*full*/ true)) continue; diff --git a/contrib/llvm-project/lldb/source/Breakpoint/Watchpoint.cpp b/contrib/llvm-project/lldb/source/Breakpoint/Watchpoint.cpp index 1a8ef87c1e67..715e83c76697 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/Watchpoint.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/Watchpoint.cpp @@ -31,8 +31,7 @@ Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size, : StoppointSite(0, addr, size, hardware), m_target(target), m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false), m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0), - m_watch_write(0), m_watch_modify(0), m_ignore_count(0), - m_being_created(true) { + m_watch_write(0), m_watch_modify(0), m_ignore_count(0) { if (type && type->IsValid()) m_type = *type; @@ -45,10 +44,16 @@ Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size, LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err), "Failed to set type: {0}"); } else { - if (auto ts = *type_system_or_err) - m_type = - ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size); - else + if (auto ts = *type_system_or_err) { + if (size <= target.GetArchitecture().GetAddressByteSize()) { + m_type = + ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size); + } else { + CompilerType clang_uint8_type = + ts->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8); + m_type = clang_uint8_type.GetArrayType(size); + } + } else LLDB_LOG_ERROR(GetLog(LLDBLog::Watchpoints), std::move(err), "Failed to set type: Typesystem is no longer live: {0}"); } @@ -60,7 +65,6 @@ Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size, m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx); CaptureWatchedValue(exe_ctx); } - m_being_created = false; } Watchpoint::~Watchpoint() = default; @@ -295,7 +299,9 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const { .SetHideRootType(true) .SetHideRootName(true) .SetHideName(true); - m_old_value_sp->Dump(strm, options); + if (llvm::Error error = m_old_value_sp->Dump(strm, options)) + strm << "error: " << toString(std::move(error)); + if (strm.GetData()) values_ss.Printf("old value: %s", strm.GetData()); } @@ -318,7 +324,9 @@ bool Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const { .SetHideRootType(true) .SetHideRootName(true) .SetHideName(true); - m_new_value_sp->Dump(strm, options); + if (llvm::Error error = m_new_value_sp->Dump(strm, options)) + strm << "error: " << toString(std::move(error)); + if (strm.GetData()) values_ss.Printf("new value: %s", strm.GetData()); } @@ -352,6 +360,20 @@ void Watchpoint::DumpWithLevel(Stream *s, s->Printf("\n declare @ '%s'", m_decl_str.c_str()); if (!m_watch_spec_str.empty()) s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str()); + if (IsEnabled()) { + if (ProcessSP process_sp = m_target.GetProcessSP()) { + auto &resourcelist = process_sp->GetWatchpointResourceList(); + size_t idx = 0; + s->Printf("\n watchpoint resources:"); + for (WatchpointResourceSP &wpres : resourcelist.Sites()) { + if (wpres->ConstituentsContains(this)) { + s->Printf("\n #%zu: ", idx); + wpres->Dump(s); + } + idx++; + } + } + } // Dump the snapshots we have taken. DumpSnapshots(s, " "); @@ -442,9 +464,8 @@ void Watchpoint::SetCondition(const char *condition) { // Pass nullptr for expr_prefix (no translation-unit level definitions). Status error; m_condition_up.reset(m_target.GetUserExpressionForLanguage( - condition, llvm::StringRef(), lldb::eLanguageTypeUnknown, - UserExpression::eResultTypeAny, EvaluateExpressionOptions(), nullptr, - error)); + condition, {}, {}, UserExpression::eResultTypeAny, + EvaluateExpressionOptions(), nullptr, error)); if (error.Fail()) { // FIXME: Log something... m_condition_up.reset(); @@ -462,8 +483,8 @@ const char *Watchpoint::GetConditionText() const { void Watchpoint::SendWatchpointChangedEvent( lldb::WatchpointEventType eventKind) { - if (!m_being_created && GetTarget().EventTypeHasListeners( - Target::eBroadcastBitWatchpointChanged)) { + if (GetTarget().EventTypeHasListeners( + Target::eBroadcastBitWatchpointChanged)) { auto data_sp = std::make_shared<WatchpointEventData>(eventKind, shared_from_this()); GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged, data_sp); diff --git a/contrib/llvm-project/lldb/source/Breakpoint/WatchpointAlgorithms.cpp b/contrib/llvm-project/lldb/source/Breakpoint/WatchpointAlgorithms.cpp new file mode 100644 index 000000000000..3caf29b04317 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Breakpoint/WatchpointAlgorithms.cpp @@ -0,0 +1,158 @@ +//===-- WatchpointAlgorithms.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Breakpoint/WatchpointAlgorithms.h" +#include "lldb/Breakpoint/WatchpointResource.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include <algorithm> +#include <utility> +#include <vector> + +using namespace lldb; +using namespace lldb_private; + +std::vector<WatchpointResourceSP> +WatchpointAlgorithms::AtomizeWatchpointRequest( + addr_t addr, size_t size, bool read, bool write, + WatchpointHardwareFeature supported_features, ArchSpec &arch) { + + std::vector<Region> entries; + + if (supported_features & eWatchpointHardwareArmMASK) { + entries = + PowerOf2Watchpoints(addr, size, + /*min_byte_size*/ 1, + /*max_byte_size*/ INT32_MAX, + /*address_byte_size*/ arch.GetAddressByteSize()); + } else { + // As a fallback, assume we can watch any power-of-2 + // number of bytes up through the size of an address in the target. + entries = + PowerOf2Watchpoints(addr, size, + /*min_byte_size*/ 1, + /*max_byte_size*/ arch.GetAddressByteSize(), + /*address_byte_size*/ arch.GetAddressByteSize()); + } + + Log *log = GetLog(LLDBLog::Watchpoints); + LLDB_LOGV(log, "AtomizeWatchpointRequest user request addr {0:x} size {1}", + addr, size); + std::vector<WatchpointResourceSP> resources; + for (Region &ent : entries) { + LLDB_LOGV(log, "AtomizeWatchpointRequest creating resource {0:x} size {1}", + ent.addr, ent.size); + WatchpointResourceSP wp_res_sp = + std::make_shared<WatchpointResource>(ent.addr, ent.size, read, write); + resources.push_back(wp_res_sp); + } + + return resources; +} + +// This should be `std::bit_ceil(aligned_size)` but +// that requires C++20. +// Calculates the smallest integral power of two that is not smaller than x. +static uint64_t bit_ceil(uint64_t input) { + if (input <= 1 || llvm::popcount(input) == 1) + return input; + + return 1ULL << (64 - llvm::countl_zero(input)); +} + +/// Convert a user's watchpoint request (\a user_addr and \a user_size) +/// into hardware watchpoints, for a target that can watch a power-of-2 +/// region of memory (1, 2, 4, 8, etc), aligned to that same power-of-2 +/// memory address. +/// +/// If a user asks to watch 4 bytes at address 0x1002 (0x1002-0x1005 +/// inclusive) we can implement this with two 2-byte watchpoints +/// (0x1002 and 0x1004) or with an 8-byte watchpoint at 0x1000. +/// A 4-byte watchpoint at 0x1002 would not be properly 4 byte aligned. +/// +/// If a user asks to watch 16 bytes at 0x1000, and this target supports +/// 8-byte watchpoints, we can implement this with two 8-byte watchpoints +/// at 0x1000 and 0x1008. +std::vector<WatchpointAlgorithms::Region> +WatchpointAlgorithms::PowerOf2Watchpoints(addr_t user_addr, size_t user_size, + size_t min_byte_size, + size_t max_byte_size, + uint32_t address_byte_size) { + + Log *log = GetLog(LLDBLog::Watchpoints); + LLDB_LOGV(log, + "AtomizeWatchpointRequest user request addr {0:x} size {1} " + "min_byte_size {2}, max_byte_size {3}, address_byte_size {4}", + user_addr, user_size, min_byte_size, max_byte_size, + address_byte_size); + + // Can't watch zero bytes. + if (user_size == 0) + return {}; + + size_t aligned_size = std::max(user_size, min_byte_size); + /// Round up \a user_size to the next power-of-2 size + /// user_size == 8 -> aligned_size == 8 + /// user_size == 9 -> aligned_size == 16 + aligned_size = bit_ceil(aligned_size); + + addr_t aligned_start = user_addr & ~(aligned_size - 1); + + // Does this power-of-2 memory range, aligned to power-of-2 that the + // hardware can watch, completely cover the requested region. + if (aligned_size <= max_byte_size && + aligned_start + aligned_size >= user_addr + user_size) + return {{aligned_start, aligned_size}}; + + // If the maximum region we can watch is larger than the aligned + // size, try increasing the region size by one power of 2 and see + // if aligning to that amount can cover the requested region. + // + // Increasing the aligned_size repeatedly instead of splitting the + // watchpoint can result in us watching large regions of memory + // unintentionally when we could use small two watchpoints. e.g. + // user_addr 0x3ff8 user_size 32 + // can be watched with four 8-byte watchpoints or if it's done with one + // MASK watchpoint, it would need to be a 32KB watchpoint (a 16KB + // watchpoint at 0x0 only covers 0x0000-0x4000). A user request + // at the end of a power-of-2 region can lead to these undesirably + // large watchpoints and many false positive hits to ignore. + if (max_byte_size >= (aligned_size << 1)) { + aligned_size <<= 1; + aligned_start = user_addr & ~(aligned_size - 1); + if (aligned_size <= max_byte_size && + aligned_start + aligned_size >= user_addr + user_size) + return {{aligned_start, aligned_size}}; + + // Go back to our original aligned size, to try the multiple + // watchpoint approach. + aligned_size >>= 1; + } + + // We need to split the user's watchpoint into two or more watchpoints + // that can be monitored by hardware, because of alignment and/or size + // reasons. + aligned_size = std::min(aligned_size, max_byte_size); + aligned_start = user_addr & ~(aligned_size - 1); + + std::vector<Region> result; + addr_t current_address = aligned_start; + const addr_t user_end_address = user_addr + user_size; + while (current_address + aligned_size < user_end_address) { + result.push_back({current_address, aligned_size}); + current_address += aligned_size; + } + + if (current_address < user_end_address) + result.push_back({current_address, aligned_size}); + + return result; +} diff --git a/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResource.cpp b/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResource.cpp index d0f8dc346f3c..fa0442997b52 100644 --- a/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResource.cpp +++ b/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResource.cpp @@ -9,6 +9,7 @@ #include <assert.h> #include "lldb/Breakpoint/WatchpointResource.h" +#include "lldb/Utility/Stream.h" #include <algorithm> @@ -42,8 +43,6 @@ void WatchpointResource::SetType(bool read, bool write) { wp_resource_id_t WatchpointResource::GetID() const { return m_id; } -void WatchpointResource::SetID(wp_resource_id_t id) { m_id = id; } - bool WatchpointResource::Contains(addr_t addr) { if (addr >= m_addr && addr < m_addr + m_size) return true; @@ -115,7 +114,7 @@ bool WatchpointResource::ShouldStop(StoppointCallbackContext *context) { } void WatchpointResource::Dump(Stream *s) const { - return; // LWP_TODO + s->Printf("addr = 0x%8.8" PRIx64 " size = %zu", m_addr, m_size); } wp_resource_id_t WatchpointResource::GetNextID() { diff --git a/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResourceList.cpp b/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResourceList.cpp deleted file mode 100644 index d1d364832098..000000000000 --- a/contrib/llvm-project/lldb/source/Breakpoint/WatchpointResourceList.cpp +++ /dev/null @@ -1,114 +0,0 @@ -//===-- WatchpointResourceList.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Breakpoint/WatchpointResourceList.h" -#include "lldb/Breakpoint/WatchpointResource.h" -#include "lldb/Utility/LLDBLog.h" -#include "lldb/Utility/Log.h" - -using namespace lldb; -using namespace lldb_private; - -WatchpointResourceList::WatchpointResourceList() : m_resources(), m_mutex() {} - -WatchpointResourceList::~WatchpointResourceList() { Clear(); } - -wp_resource_id_t -WatchpointResourceList::Add(const WatchpointResourceSP &wp_res_sp) { - Log *log = GetLog(LLDBLog::Watchpoints); - std::lock_guard<std::mutex> guard(m_mutex); - LLDB_LOGF(log, "WatchpointResourceList::Add(addr 0x%" PRIx64 " size %zu)", - wp_res_sp->GetLoadAddress(), wp_res_sp->GetByteSize()); - - m_resources.push_back(wp_res_sp); - return wp_res_sp->GetID(); -} - -bool WatchpointResourceList::Remove(wp_resource_id_t id) { - std::lock_guard<std::mutex> guard(m_mutex); - Log *log = GetLog(LLDBLog::Watchpoints); - for (collection::iterator pos = m_resources.begin(); pos != m_resources.end(); - ++pos) { - if ((*pos)->GetID() == id) { - LLDB_LOGF(log, - "WatchpointResourceList::Remove(addr 0x%" PRIx64 " size %zu)", - (*pos)->GetLoadAddress(), (*pos)->GetByteSize()); - m_resources.erase(pos); - return true; - } - } - return false; -} - -bool WatchpointResourceList::RemoveByAddress(addr_t addr) { - std::lock_guard<std::mutex> guard(m_mutex); - Log *log = GetLog(LLDBLog::Watchpoints); - for (collection::iterator pos = m_resources.begin(); pos != m_resources.end(); - ++pos) { - if ((*pos)->Contains(addr)) { - LLDB_LOGF(log, - "WatchpointResourceList::RemoveByAddress(addr 0x%" PRIx64 - " size %zu)", - (*pos)->GetLoadAddress(), (*pos)->GetByteSize()); - m_resources.erase(pos); - return true; - } - } - return false; -} - -WatchpointResourceSP WatchpointResourceList::FindByAddress(addr_t addr) { - std::lock_guard<std::mutex> guard(m_mutex); - for (WatchpointResourceSP wp_res_sp : m_resources) - if (wp_res_sp->Contains(addr)) - return wp_res_sp; - return {}; -} - -WatchpointResourceSP -WatchpointResourceList::FindByWatchpointSP(WatchpointSP &wp_sp) { - return FindByWatchpoint(wp_sp.get()); -} - -WatchpointResourceSP -WatchpointResourceList::FindByWatchpoint(const Watchpoint *wp) { - std::lock_guard<std::mutex> guard(m_mutex); - for (WatchpointResourceSP wp_res_sp : m_resources) - if (wp_res_sp->ConstituentsContains(wp)) - return wp_res_sp; - return {}; -} - -WatchpointResourceSP WatchpointResourceList::FindByID(wp_resource_id_t id) { - std::lock_guard<std::mutex> guard(m_mutex); - for (WatchpointResourceSP wp_res_sp : m_resources) - if (wp_res_sp->GetID() == id) - return wp_res_sp; - return {}; -} - -uint32_t WatchpointResourceList::GetSize() { - std::lock_guard<std::mutex> guard(m_mutex); - return m_resources.size(); -} - -lldb::WatchpointResourceSP -WatchpointResourceList::GetResourceAtIndex(uint32_t idx) { - std::lock_guard<std::mutex> guard(m_mutex); - if (idx < m_resources.size()) - return m_resources[idx]; - - return {}; -} - -void WatchpointResourceList::Clear() { - std::lock_guard<std::mutex> guard(m_mutex); - m_resources.clear(); -} - -std::mutex &WatchpointResourceList::GetMutex() { return m_mutex; } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp b/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp index 16078a92ab5f..54f4b3681664 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandCompletions.cpp @@ -6,7 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "lldb/Breakpoint/Watchpoint.h" @@ -262,9 +264,25 @@ class ModuleCompleter : public Completer { public: ModuleCompleter(CommandInterpreter &interpreter, CompletionRequest &request) : Completer(interpreter, request) { - FileSpec partial_spec(m_request.GetCursorArgumentPrefix()); - m_file_name = partial_spec.GetFilename().GetCString(); - m_dir_name = partial_spec.GetDirectory().GetCString(); + llvm::StringRef request_str = m_request.GetCursorArgumentPrefix(); + // We can match the full path, or the file name only. The full match will be + // attempted always, the file name match only if the request does not + // contain a path separator. + + // Preserve both the path as spelled by the user (used for completion) and + // the canonical version (used for matching). + m_spelled_path = request_str; + m_canonical_path = FileSpec(m_spelled_path).GetPath(); + if (!m_spelled_path.empty() && + llvm::sys::path::is_separator(m_spelled_path.back()) && + !llvm::StringRef(m_canonical_path).ends_with(m_spelled_path.back())) { + m_canonical_path += m_spelled_path.back(); + } + + if (llvm::find_if(request_str, [](char c) { + return llvm::sys::path::is_separator(c); + }) == request_str.end()) + m_file_name = request_str; } lldb::SearchDepth GetDepth() override { return lldb::eSearchDepthModule; } @@ -273,22 +291,18 @@ public: SymbolContext &context, Address *addr) override { if (context.module_sp) { - const char *cur_file_name = - context.module_sp->GetFileSpec().GetFilename().GetCString(); - const char *cur_dir_name = - context.module_sp->GetFileSpec().GetDirectory().GetCString(); - - bool match = false; - if (m_file_name && cur_file_name && - strstr(cur_file_name, m_file_name) == cur_file_name) - match = true; - - if (match && m_dir_name && cur_dir_name && - strstr(cur_dir_name, m_dir_name) != cur_dir_name) - match = false; - - if (match) { - m_request.AddCompletion(cur_file_name); + // Attempt a full path match. + std::string cur_path = context.module_sp->GetFileSpec().GetPath(); + llvm::StringRef cur_path_view = cur_path; + if (cur_path_view.consume_front(m_canonical_path)) + m_request.AddCompletion((m_spelled_path + cur_path_view).str()); + + // And a file name match. + if (m_file_name) { + llvm::StringRef cur_file_name = + context.module_sp->GetFileSpec().GetFilename().GetStringRef(); + if (cur_file_name.starts_with(*m_file_name)) + m_request.AddCompletion(cur_file_name); } } return Searcher::eCallbackReturnContinue; @@ -297,8 +311,9 @@ public: void DoCompletion(SearchFilter *filter) override { filter->Search(*this); } private: - const char *m_file_name; - const char *m_dir_name; + std::optional<llvm::StringRef> m_file_name; + llvm::StringRef m_spelled_path; + std::string m_canonical_path; ModuleCompleter(const ModuleCompleter &) = delete; const ModuleCompleter &operator=(const ModuleCompleter &) = delete; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectApropos.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectApropos.cpp index 88c214d4fc56..d663f2bd923f 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectApropos.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectApropos.cpp @@ -21,19 +21,7 @@ CommandObjectApropos::CommandObjectApropos(CommandInterpreter &interpreter) : CommandObjectParsed( interpreter, "apropos", "List debugger commands related to a word or subject.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData search_word_arg; - - // Define the first (and only) variant of this arg. - search_word_arg.arg_type = eArgTypeSearchWord; - search_word_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument - // entry. - arg.push_back(search_word_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeSearchWord); } CommandObjectApropos::~CommandObjectApropos() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp index 1661d5d9b743..773f8ed2fa8a 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -64,6 +64,8 @@ public: Status error; const int short_option = g_breakpoint_modify_options[option_idx].short_option; + const char *long_option = + g_breakpoint_modify_options[option_idx].long_option; switch (short_option) { case 'c': @@ -84,18 +86,17 @@ public: case 'G': { bool value, success; value = OptionArgParser::ToBoolean(option_arg, false, &success); - if (success) { + if (success) m_bp_opts.SetAutoContinue(value); - } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -G option", - option_arg.str().c_str()); + else + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'i': { uint32_t ignore_count; if (option_arg.getAsInteger(0, ignore_count)) - error.SetErrorStringWithFormat("invalid ignore count '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); else m_bp_opts.SetIgnoreCount(ignore_count); } break; @@ -105,27 +106,29 @@ public: if (success) { m_bp_opts.SetOneShot(value); } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -o option", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 't': { lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID; if (option_arg == "current") { if (!execution_context) { - error.SetErrorStringWithFormat("No context to determine current " - "thread"); + error = CreateOptionParsingError( + option_arg, short_option, long_option, + "No context to determine current thread"); } else { ThreadSP ctx_thread_sp = execution_context->GetThreadSP(); if (!ctx_thread_sp || !ctx_thread_sp->IsValid()) { - error.SetErrorStringWithFormat("No currently selected thread"); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + "No currently selected thread"); } else { thread_id = ctx_thread_sp->GetID(); } } } else if (option_arg.getAsInteger(0, thread_id)) { - error.SetErrorStringWithFormat("invalid thread id string '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); } if (thread_id != LLDB_INVALID_THREAD_ID) m_bp_opts.SetThreadID(thread_id); @@ -139,8 +142,8 @@ public: case 'x': { uint32_t thread_index = UINT32_MAX; if (option_arg.getAsInteger(0, thread_index)) { - error.SetErrorStringWithFormat("invalid thread index string '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); } else { m_bp_opts.GetThreadSpec()->SetIndex(thread_index); } @@ -263,6 +266,8 @@ public: Status error; const int short_option = g_breakpoint_set_options[option_idx].short_option; + const char *long_option = + g_breakpoint_set_options[option_idx].long_option; switch (short_option) { case 'a': { @@ -281,13 +286,15 @@ public: case 'u': if (option_arg.getAsInteger(0, m_column)) - error.SetErrorStringWithFormat("invalid column number: %s", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); break; case 'E': { LanguageType language = Language::GetLanguageTypeFromString(option_arg); + llvm::StringRef error_context; switch (language) { case eLanguageTypeC89: case eLanguageTypeC: @@ -301,23 +308,26 @@ public: case eLanguageTypeC_plus_plus_14: m_exception_language = eLanguageTypeC_plus_plus; break; - case eLanguageTypeObjC: - m_exception_language = eLanguageTypeObjC; - break; case eLanguageTypeObjC_plus_plus: - error.SetErrorStringWithFormat( - "Set exception breakpoints separately for c++ and objective-c"); + error_context = + "Set exception breakpoints separately for c++ and objective-c"; break; case eLanguageTypeUnknown: - error.SetErrorStringWithFormat( - "Unknown language type: '%s' for exception breakpoint", - option_arg.str().c_str()); + error_context = "Unknown language type for exception breakpoint"; break; default: - error.SetErrorStringWithFormat( - "Unsupported language type: '%s' for exception breakpoint", - option_arg.str().c_str()); + if (Language *languagePlugin = Language::FindPlugin(language)) { + if (languagePlugin->SupportsExceptionBreakpointsOnThrow() || + languagePlugin->SupportsExceptionBreakpointsOnCatch()) { + m_exception_language = language; + break; + } + } + error_context = "Unsupported language type for exception breakpoint"; } + if (!error_context.empty()) + error = CreateOptionParsingError(option_arg, short_option, + long_option, error_context); } break; case 'f': @@ -333,9 +343,9 @@ public: bool success; m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success); if (!success) - error.SetErrorStringWithFormat( - "Invalid boolean value for on-catch option: '%s'", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'H': @@ -352,23 +362,24 @@ public: m_skip_prologue = eLazyBoolNo; if (!success) - error.SetErrorStringWithFormat( - "Invalid boolean value for skip prologue option: '%s'", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'l': if (option_arg.getAsInteger(0, m_line_num)) - error.SetErrorStringWithFormat("invalid line number: %s.", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); break; case 'L': m_language = Language::GetLanguageTypeFromString(option_arg); if (m_language == eLanguageTypeUnknown) - error.SetErrorStringWithFormat( - "Unknown language type: '%s' for breakpoint", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_language_parsing_error_message); break; case 'm': { @@ -381,9 +392,9 @@ public: m_move_to_nearest_code = eLazyBoolNo; if (!success) - error.SetErrorStringWithFormat( - "Invalid boolean value for move-to-nearest-code option: '%s'", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); break; } @@ -401,8 +412,8 @@ public: if (BreakpointID::StringIsBreakpointName(option_arg, error)) m_breakpoint_names.push_back(std::string(option_arg)); else - error.SetErrorStringWithFormat("Invalid breakpoint name: %s", - option_arg.str().c_str()); + error = CreateOptionParsingError( + option_arg, short_option, long_option, "Invalid breakpoint name"); break; } @@ -440,9 +451,9 @@ public: bool success; m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success); if (!success) - error.SetErrorStringWithFormat( - "Invalid boolean value for on-throw option: '%s'", - option_arg.str().c_str()); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'X': @@ -454,9 +465,8 @@ public: OptionValueFileColonLine value; Status fcl_err = value.SetValueFromString(option_arg); if (!fcl_err.Success()) { - error.SetErrorStringWithFormat( - "Invalid value for file:line specifier: %s", - fcl_err.AsCString()); + error = CreateOptionParsingError(option_arg, short_option, + long_option, fcl_err.AsCString()); } else { m_filenames.AppendIfUnique(value.GetFileSpec()); m_line_num = value.GetLineNumber(); @@ -774,8 +784,8 @@ private: } else { const SymbolContext &sc = cur_frame->GetSymbolContext(eSymbolContextLineEntry); - if (sc.line_entry.file) { - file = sc.line_entry.file; + if (sc.line_entry.GetFile()) { + file = sc.line_entry.GetFile(); } else { result.AppendError("Can't find the file for the selected frame to " "use as the default file."); @@ -807,12 +817,7 @@ public: "With the exception of -e, -d and -i, passing an " "empty argument clears the modification.", nullptr) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, - eArgTypeBreakpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eBreakpointArgs); m_options.Append(&m_bp_opts, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, @@ -884,12 +889,7 @@ public: "Enable the specified disabled breakpoint(s). If " "no breakpoints are specified, enable all of them.", nullptr) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, - eArgTypeBreakpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eBreakpointArgs); } ~CommandObjectBreakpointEnable() override = default; @@ -996,12 +996,7 @@ execution will NOT stop at location 1.1. To achieve that, type: "The first command disables all locations for breakpoint 1, \ the second re-enables the first location."); - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, - eArgTypeBreakpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eBreakpointArgs); } ~CommandObjectBreakpointDisable() override = default; @@ -1092,15 +1087,7 @@ public: CommandArgumentData bp_id_arg; // Define the first (and only) variant of this arg. - bp_id_arg.arg_type = eArgTypeBreakpointID; - bp_id_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(bp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional); } ~CommandObjectBreakpointList() override = default; @@ -1366,12 +1353,7 @@ public: "Delete the specified breakpoint(s). If no " "breakpoints are specified, delete them all.", nullptr) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, - eArgTypeBreakpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eBreakpointArgs); } ~CommandObjectBreakpointDelete() override = default; @@ -1485,9 +1467,8 @@ protected: for (auto breakpoint_sp : breakpoints.Breakpoints()) { if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) { BreakpointID bp_id(breakpoint_sp->GetID()); - size_t pos = 0; - if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos)) - valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID()); + if (!excluded_bp_ids.Contains(bp_id)) + valid_bp_ids.AddBreakpointID(bp_id); } } if (valid_bp_ids.GetSize() == 0) { @@ -1555,6 +1536,7 @@ public: ExecutionContext *execution_context) override { Status error; const int short_option = g_breakpoint_name_options[option_idx].short_option; + const char *long_option = g_breakpoint_name_options[option_idx].long_option; switch (short_option) { case 'N': @@ -1564,15 +1546,13 @@ public: break; case 'B': if (m_breakpoint.SetValueFromString(option_arg).Fail()) - error.SetErrorStringWithFormat( - "unrecognized value \"%s\" for breakpoint", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); break; case 'D': if (m_use_dummy.SetValueFromString(option_arg).Fail()) - error.SetErrorStringWithFormat( - "unrecognized value \"%s\" for use-dummy", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); break; case 'H': m_help_string.SetValueFromString(option_arg); @@ -1615,6 +1595,8 @@ public: Status error; const int short_option = g_breakpoint_access_options[option_idx].short_option; + const char *long_option = + g_breakpoint_access_options[option_idx].long_option; switch (short_option) { case 'L': { @@ -1623,9 +1605,8 @@ public: if (success) { m_permissions.SetAllowList(value); } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -L option", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'A': { bool value, success; @@ -1633,9 +1614,8 @@ public: if (success) { m_permissions.SetAllowDisable(value); } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -L option", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'D': { bool value, success; @@ -1643,9 +1623,8 @@ public: if (success) { m_permissions.SetAllowDelete(value); } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -L option", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; default: llvm_unreachable("Unimplemented option"); @@ -1674,14 +1653,7 @@ public: "on the name.", "breakpoint name configure <command-options> " "<breakpoint-name-list>") { - // Create the first variant for the first (and only) argument for this - // command. - CommandArgumentEntry arg1; - CommandArgumentData id_arg; - id_arg.arg_type = eArgTypeBreakpointName; - id_arg.arg_repetition = eArgRepeatOptional; - arg1.push_back(id_arg); - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeBreakpointName, eArgRepeatOptional); m_option_group.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_access_options, LLDB_OPT_SET_ALL, @@ -1767,14 +1739,7 @@ public: : CommandObjectParsed( interpreter, "add", "Add a name to the breakpoints provided.", "breakpoint name add <command-options> <breakpoint-id-list>") { - // Create the first variant for the first (and only) argument for this - // command. - CommandArgumentEntry arg1; - CommandArgumentData id_arg; - id_arg.arg_type = eArgTypeBreakpointID; - id_arg.arg_repetition = eArgRepeatOptional; - arg1.push_back(id_arg); - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional); m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); m_option_group.Finalize(); @@ -1848,14 +1813,7 @@ public: interpreter, "delete", "Delete a name from the breakpoints provided.", "breakpoint name delete <command-options> <breakpoint-id-list>") { - // Create the first variant for the first (and only) argument for this - // command. - CommandArgumentEntry arg1; - CommandArgumentData id_arg; - id_arg.arg_type = eArgTypeBreakpointID; - id_arg.arg_repetition = eArgRepeatOptional; - arg1.push_back(id_arg); - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional); m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); m_option_group.Finalize(); @@ -2139,6 +2097,8 @@ public: ExecutionContext *execution_context) override { Status error; const int short_option = m_getopt_table[option_idx].val; + const char *long_option = + m_getopt_table[option_idx].definition->long_option; switch (short_option) { case 'f': @@ -2148,8 +2108,8 @@ public: Status name_error; if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg), name_error)) { - error.SetErrorStringWithFormat("Invalid breakpoint name: %s", - name_error.AsCString()); + error = CreateOptionParsingError(option_arg, short_option, + long_option, name_error.AsCString()); } m_names.push_back(std::string(option_arg)); break; @@ -2303,12 +2263,7 @@ public: "be read in with \"breakpoint read\". " "If given no arguments, writes all breakpoints.", nullptr) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, - eArgTypeBreakpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eBreakpointArgs); } ~CommandObjectBreakpointWrite() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index fefafcd94546..6ebe6e8a3557 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -185,19 +185,7 @@ are no syntax errors may indicate that a function was declared but never called. LLDB_OPT_SET_2); m_all_options.Finalize(); - CommandArgumentEntry arg; - CommandArgumentData bp_id_arg; - - // Define the first (and only) variant of this arg. - bp_id_arg.arg_type = eArgTypeBreakpointID; - bp_id_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(bp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional); } ~CommandObjectBreakpointCommandAdd() override = default; @@ -449,19 +437,7 @@ public: : CommandObjectParsed(interpreter, "delete", "Delete the set of commands from a breakpoint.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData bp_id_arg; - - // Define the first (and only) variant of this arg. - bp_id_arg.arg_type = eArgTypeBreakpointID; - bp_id_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(bp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeBreakpointID); } ~CommandObjectBreakpointCommandDelete() override = default; @@ -565,19 +541,7 @@ public: "List the script or set of commands to be " "executed when the breakpoint is hit.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandArgumentData bp_id_arg; - - // Define the first (and only) variant of this arg. - bp_id_arg.arg_type = eArgTypeBreakpointID; - bp_id_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(bp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeBreakpointID); } ~CommandObjectBreakpointCommandList() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp index 5b9af4a3e1b8..c63445b7c8c8 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectCommands.cpp @@ -41,19 +41,7 @@ public: interpreter, "command source", "Read and execute LLDB commands from the file <filename>.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData file_arg; - - // Define the first (and only) variant of this arg. - file_arg.arg_type = eArgTypeFilename; - file_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFilename); } ~CommandObjectCommandsSource() override = default; @@ -63,13 +51,6 @@ public: return std::string(""); } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - Options *GetOptions() override { return &m_options; } protected: @@ -621,19 +602,7 @@ public: interpreter, "command unalias", "Delete one or more custom commands defined by 'command alias'.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData alias_arg; - - // Define the first (and only) variant of this arg. - alias_arg.arg_type = eArgTypeAliasName; - alias_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(alias_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeAliasName); } ~CommandObjectCommandsUnalias() override = default; @@ -708,19 +677,7 @@ public: interpreter, "command delete", "Delete one or more custom commands defined by 'command regex'.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData alias_arg; - - // Define the first (and only) variant of this arg. - alias_arg.arg_type = eArgTypeCommandName; - alias_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(alias_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeCommandName); } ~CommandObjectCommandsDelete() override = default; @@ -822,8 +779,7 @@ a number follows 'f':" R"( (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); - CommandArgumentData thread_arg{eArgTypeSEDStylePair, eArgRepeatOptional}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeSEDStylePair, eArgRepeatOptional); } ~CommandObjectCommandsAddRegex() override = default; @@ -1123,6 +1079,8 @@ protected: CommandReturnObject &result) override { ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + m_interpreter.IncreaseCommandUsage(*this); + Status error; result.SetStatus(eReturnStatusInvalid); @@ -1149,13 +1107,16 @@ private: CompletionType m_completion_type = eNoCompletion; }; -class CommandObjectScriptingObject : public CommandObjectRaw { +/// This class implements a "raw" scripted command. lldb does no parsing of the +/// command line, instead passing the line unaltered (except for backtick +/// substitution). +class CommandObjectScriptingObjectRaw : public CommandObjectRaw { public: - CommandObjectScriptingObject(CommandInterpreter &interpreter, - std::string name, - StructuredData::GenericSP cmd_obj_sp, - ScriptedCommandSynchronicity synch, - CompletionType completion_type) + CommandObjectScriptingObjectRaw(CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch, + CompletionType completion_type) : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), m_fetched_help_short(false), m_fetched_help_long(false), m_completion_type(completion_type) { @@ -1166,7 +1127,7 @@ public: GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); } - ~CommandObjectScriptingObject() override = default; + ~CommandObjectScriptingObjectRaw() override = default; void HandleArgumentCompletion(CompletionRequest &request, @@ -1181,6 +1142,15 @@ public: ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } + std::optional<std::string> GetRepeatCommand(Args &args, + uint32_t index) override { + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + if (!scripter) + return std::nullopt; + + return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); + } + llvm::StringRef GetHelp() override { if (m_fetched_help_short) return CommandObjectRaw::GetHelp(); @@ -1244,6 +1214,715 @@ private: CompletionType m_completion_type = eNoCompletion; }; + +/// This command implements a lldb parsed scripted command. The command +/// provides a definition of the options and arguments, and a option value +/// setting callback, and then the command's execution function gets passed +/// just the parsed arguments. +/// Note, implementing a command in Python using these base interfaces is a bit +/// of a pain, but it is much easier to export this low level interface, and +/// then make it nicer on the Python side, than to try to do that in a +/// script language neutral way. +/// So I've also added a base class in Python that provides a table-driven +/// way of defining the options and arguments, which automatically fills the +/// option values, making them available as properties in Python. +/// +class CommandObjectScriptingObjectParsed : public CommandObjectParsed { +private: + class CommandOptions : public Options { + public: + CommandOptions(CommandInterpreter &interpreter, + StructuredData::GenericSP cmd_obj_sp) : m_interpreter(interpreter), + m_cmd_obj_sp(cmd_obj_sp) {} + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + ScriptInterpreter *scripter = + m_interpreter.GetDebugger().GetScriptInterpreter(); + if (!scripter) { + error.SetErrorString("No script interpreter for SetOptionValue."); + return error; + } + if (!m_cmd_obj_sp) { + error.SetErrorString("SetOptionValue called with empty cmd_obj."); + return error; + } + if (!m_options_definition_up) { + error.SetErrorString("SetOptionValue called before options definitions " + "were created."); + return error; + } + // Pass the long option, since you aren't actually required to have a + // short_option, and for those options the index or short option character + // aren't meaningful on the python side. + const char * long_option = + m_options_definition_up.get()[option_idx].long_option; + bool success = scripter->SetOptionValueForCommandObject(m_cmd_obj_sp, + execution_context, long_option, option_arg); + if (!success) + error.SetErrorStringWithFormatv("Error setting option: {0} to {1}", + long_option, option_arg); + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + ScriptInterpreter *scripter = + m_interpreter.GetDebugger().GetScriptInterpreter(); + if (!scripter || !m_cmd_obj_sp) + return; + + scripter->OptionParsingStartedForCommandObject(m_cmd_obj_sp); + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + if (!m_options_definition_up) + return {}; + return llvm::ArrayRef(m_options_definition_up.get(), m_num_options); + } + + static Status ParseUsageMaskFromArray(StructuredData::ObjectSP obj_sp, + size_t counter, uint32_t &usage_mask) { + // If the usage entry is not provided, we use LLDB_OPT_SET_ALL. + // If the usage mask is a UINT, the option belongs to that group. + // If the usage mask is a vector of UINT's, the option belongs to all the + // groups listed. + // If a subelement of the vector is a vector of two ints, then the option + // belongs to the inclusive range from the first to the second element. + Status error; + if (!obj_sp) { + usage_mask = LLDB_OPT_SET_ALL; + return error; + } + + usage_mask = 0; + + StructuredData::UnsignedInteger *uint_val = + obj_sp->GetAsUnsignedInteger(); + if (uint_val) { + // If this is an integer, then this specifies a single group: + uint32_t value = uint_val->GetValue(); + if (value == 0) { + error.SetErrorStringWithFormatv( + "0 is not a valid group for option {0}", counter); + return error; + } + usage_mask = (1 << (value - 1)); + return error; + } + // Otherwise it has to be an array: + StructuredData::Array *array_val = obj_sp->GetAsArray(); + if (!array_val) { + error.SetErrorStringWithFormatv( + "required field is not a array for option {0}", counter); + return error; + } + // This is the array ForEach for accumulating a group usage mask from + // an array of string descriptions of groups. + auto groups_accumulator + = [counter, &usage_mask, &error] + (StructuredData::Object *obj) -> bool { + StructuredData::UnsignedInteger *int_val = obj->GetAsUnsignedInteger(); + if (int_val) { + uint32_t value = int_val->GetValue(); + if (value == 0) { + error.SetErrorStringWithFormatv( + "0 is not a valid group for element {0}", counter); + return false; + } + usage_mask |= (1 << (value - 1)); + return true; + } + StructuredData::Array *arr_val = obj->GetAsArray(); + if (!arr_val) { + error.SetErrorStringWithFormatv( + "Group element not an int or array of integers for element {0}", + counter); + return false; + } + size_t num_range_elem = arr_val->GetSize(); + if (num_range_elem != 2) { + error.SetErrorStringWithFormatv( + "Subranges of a group not a start and a stop for element {0}", + counter); + return false; + } + int_val = arr_val->GetItemAtIndex(0)->GetAsUnsignedInteger(); + if (!int_val) { + error.SetErrorStringWithFormatv("Start element of a subrange of a " + "group not unsigned int for element {0}", counter); + return false; + } + uint32_t start = int_val->GetValue(); + int_val = arr_val->GetItemAtIndex(1)->GetAsUnsignedInteger(); + if (!int_val) { + error.SetErrorStringWithFormatv("End element of a subrange of a group" + " not unsigned int for element {0}", counter); + return false; + } + uint32_t end = int_val->GetValue(); + if (start == 0 || end == 0 || start > end) { + error.SetErrorStringWithFormatv("Invalid subrange of a group: {0} - " + "{1} for element {2}", start, end, counter); + return false; + } + for (uint32_t i = start; i <= end; i++) { + usage_mask |= (1 << (i - 1)); + } + return true; + }; + array_val->ForEach(groups_accumulator); + return error; + } + + + Status SetOptionsFromArray(StructuredData::Dictionary &options) { + Status error; + m_num_options = options.GetSize(); + m_options_definition_up.reset(new OptionDefinition[m_num_options]); + // We need to hand out pointers to contents of these vectors; we reserve + // as much as we'll need up front so they don't get freed on resize... + m_usage_container.resize(m_num_options); + m_enum_storage.resize(m_num_options); + m_enum_vector.resize(m_num_options); + + size_t counter = 0; + size_t short_opt_counter = 0; + // This is the Array::ForEach function for adding option elements: + auto add_element = [this, &error, &counter, &short_opt_counter] + (llvm::StringRef long_option, StructuredData::Object *object) -> bool { + StructuredData::Dictionary *opt_dict = object->GetAsDictionary(); + if (!opt_dict) { + error.SetErrorString("Value in options dictionary is not a dictionary"); + return false; + } + OptionDefinition &option_def = m_options_definition_up.get()[counter]; + + // We aren't exposing the validator yet, set it to null + option_def.validator = nullptr; + // We don't require usage masks, so set it to one group by default: + option_def.usage_mask = 1; + + // Now set the fields of the OptionDefinition Array from the dictionary: + // + // Note that I don't check for unknown fields in the option dictionaries + // so a scriptor can add extra elements that are helpful when they go to + // do "set_option_value" + + // Usage Mask: + StructuredData::ObjectSP obj_sp = opt_dict->GetValueForKey("groups"); + if (obj_sp) { + error = ParseUsageMaskFromArray(obj_sp, counter, + option_def.usage_mask); + if (error.Fail()) + return false; + } + + // Required: + option_def.required = false; + obj_sp = opt_dict->GetValueForKey("required"); + if (obj_sp) { + StructuredData::Boolean *boolean_val = obj_sp->GetAsBoolean(); + if (!boolean_val) { + error.SetErrorStringWithFormatv("'required' field is not a boolean " + "for option {0}", counter); + return false; + } + option_def.required = boolean_val->GetValue(); + } + + // Short Option: + int short_option; + obj_sp = opt_dict->GetValueForKey("short_option"); + if (obj_sp) { + // The value is a string, so pull the + llvm::StringRef short_str = obj_sp->GetStringValue(); + if (short_str.empty()) { + error.SetErrorStringWithFormatv("short_option field empty for " + "option {0}", counter); + return false; + } else if (short_str.size() != 1) { + error.SetErrorStringWithFormatv("short_option field has extra " + "characters for option {0}", counter); + return false; + } + short_option = (int) short_str[0]; + } else { + // If the short option is not provided, then we need a unique value + // less than the lowest printable ASCII character. + short_option = short_opt_counter++; + } + option_def.short_option = short_option; + + // Long Option is the key from the outer dict: + if (long_option.empty()) { + error.SetErrorStringWithFormatv("empty long_option for option {0}", + counter); + return false; + } + auto inserted = g_string_storer.insert(long_option.str()); + option_def.long_option = ((*(inserted.first)).data()); + + // Value Type: + obj_sp = opt_dict->GetValueForKey("value_type"); + if (obj_sp) { + StructuredData::UnsignedInteger *uint_val + = obj_sp->GetAsUnsignedInteger(); + if (!uint_val) { + error.SetErrorStringWithFormatv("Value type must be an unsigned " + "integer"); + return false; + } + uint64_t val_type = uint_val->GetValue(); + if (val_type >= eArgTypeLastArg) { + error.SetErrorStringWithFormatv("Value type {0} beyond the " + "CommandArgumentType bounds", val_type); + return false; + } + option_def.argument_type = (CommandArgumentType) val_type; + option_def.option_has_arg = true; + } else { + option_def.argument_type = eArgTypeNone; + option_def.option_has_arg = false; + } + + // Completion Type: + obj_sp = opt_dict->GetValueForKey("completion_type"); + if (obj_sp) { + StructuredData::UnsignedInteger *uint_val = obj_sp->GetAsUnsignedInteger(); + if (!uint_val) { + error.SetErrorStringWithFormatv("Completion type must be an " + "unsigned integer for option {0}", counter); + return false; + } + uint64_t completion_type = uint_val->GetValue(); + if (completion_type > eCustomCompletion) { + error.SetErrorStringWithFormatv("Completion type for option {0} " + "beyond the CompletionType bounds", completion_type); + return false; + } + option_def.completion_type = (CommandArgumentType) completion_type; + } else + option_def.completion_type = eNoCompletion; + + // Usage Text: + std::string usage_text; + obj_sp = opt_dict->GetValueForKey("help"); + if (!obj_sp) { + error.SetErrorStringWithFormatv("required usage missing from option " + "{0}", counter); + return false; + } + llvm::StringRef usage_stref; + usage_stref = obj_sp->GetStringValue(); + if (usage_stref.empty()) { + error.SetErrorStringWithFormatv("empty usage text for option {0}", + counter); + return false; + } + m_usage_container[counter] = usage_stref.str().c_str(); + option_def.usage_text = m_usage_container[counter].data(); + + // Enum Values: + + obj_sp = opt_dict->GetValueForKey("enum_values"); + if (obj_sp) { + StructuredData::Array *array = obj_sp->GetAsArray(); + if (!array) { + error.SetErrorStringWithFormatv("enum values must be an array for " + "option {0}", counter); + return false; + } + size_t num_elem = array->GetSize(); + size_t enum_ctr = 0; + m_enum_storage[counter] = std::vector<EnumValueStorage>(num_elem); + std::vector<EnumValueStorage> &curr_elem = m_enum_storage[counter]; + + // This is the Array::ForEach function for adding enum elements: + // Since there are only two fields to specify the enum, use a simple + // two element array with value first, usage second. + // counter is only used for reporting so I pass it by value here. + auto add_enum = [&enum_ctr, &curr_elem, counter, &error] + (StructuredData::Object *object) -> bool { + StructuredData::Array *enum_arr = object->GetAsArray(); + if (!enum_arr) { + error.SetErrorStringWithFormatv("Enum values for option {0} not " + "an array", counter); + return false; + } + size_t num_enum_elements = enum_arr->GetSize(); + if (num_enum_elements != 2) { + error.SetErrorStringWithFormatv("Wrong number of elements: {0} " + "for enum {1} in option {2}", + num_enum_elements, enum_ctr, counter); + return false; + } + // Enum Value: + StructuredData::ObjectSP obj_sp = enum_arr->GetItemAtIndex(0); + llvm::StringRef val_stref = obj_sp->GetStringValue(); + std::string value_cstr_str = val_stref.str().c_str(); + + // Enum Usage: + obj_sp = enum_arr->GetItemAtIndex(1); + if (!obj_sp) { + error.SetErrorStringWithFormatv("No usage for enum {0} in option " + "{1}", enum_ctr, counter); + return false; + } + llvm::StringRef usage_stref = obj_sp->GetStringValue(); + std::string usage_cstr_str = usage_stref.str().c_str(); + curr_elem[enum_ctr] = EnumValueStorage(value_cstr_str, + usage_cstr_str, enum_ctr); + + enum_ctr++; + return true; + }; // end of add_enum + + array->ForEach(add_enum); + if (!error.Success()) + return false; + // We have to have a vector of elements to set in the options, make + // that here: + for (auto &elem : curr_elem) + m_enum_vector[counter].emplace_back(elem.element); + + option_def.enum_values = llvm::ArrayRef(m_enum_vector[counter]); + } + counter++; + return true; + }; // end of add_element + + options.ForEach(add_element); + return error; + } + + size_t GetNumOptions() { return m_num_options; } + + private: + struct EnumValueStorage { + EnumValueStorage() { + element.string_value = "value not set"; + element.usage = "usage not set"; + element.value = 0; + } + + EnumValueStorage(std::string in_str_val, std::string in_usage, + size_t in_value) : value(std::move(in_str_val)), usage(std::move(in_usage)) { + SetElement(in_value); + } + + EnumValueStorage(const EnumValueStorage &in) : value(in.value), + usage(in.usage) { + SetElement(in.element.value); + } + + EnumValueStorage &operator=(const EnumValueStorage &in) { + value = in.value; + usage = in.usage; + SetElement(in.element.value); + return *this; + } + + void SetElement(size_t in_value) { + element.value = in_value; + element.string_value = value.data(); + element.usage = usage.data(); + } + + std::string value; + std::string usage; + OptionEnumValueElement element; + }; + // We have to provide char * values for the long option, usage and enum + // values, that's what the option definitions hold. + // The long option strings are quite likely to be reused in other added + // commands, so those are stored in a global set: g_string_storer. + // But the usages are much less likely to be reused, so those are stored in + // a vector in the command instance. It gets resized to the correct size + // and then filled with null-terminated strings in the std::string, so the + // are valid C-strings that won't move around. + // The enum values and descriptions are treated similarly - these aren't + // all that common so it's not worth the effort to dedup them. + size_t m_num_options = 0; + std::unique_ptr<OptionDefinition> m_options_definition_up; + std::vector<std::vector<EnumValueStorage>> m_enum_storage; + std::vector<std::vector<OptionEnumValueElement>> m_enum_vector; + std::vector<std::string> m_usage_container; + CommandInterpreter &m_interpreter; + StructuredData::GenericSP m_cmd_obj_sp; + static std::unordered_set<std::string> g_string_storer; + }; + +public: + static CommandObjectSP Create(CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch, + CommandReturnObject &result) { + CommandObjectSP new_cmd_sp(new CommandObjectScriptingObjectParsed( + interpreter, name, cmd_obj_sp, synch)); + + CommandObjectScriptingObjectParsed *parsed_cmd + = static_cast<CommandObjectScriptingObjectParsed *>(new_cmd_sp.get()); + // Now check all the failure modes, and report if found. + Status opt_error = parsed_cmd->GetOptionsError(); + Status arg_error = parsed_cmd->GetArgsError(); + + if (opt_error.Fail()) + result.AppendErrorWithFormat("failed to parse option definitions: %s", + opt_error.AsCString()); + if (arg_error.Fail()) + result.AppendErrorWithFormat("%sfailed to parse argument definitions: %s", + opt_error.Fail() ? ", also " : "", + arg_error.AsCString()); + + if (!result.Succeeded()) + return {}; + + return new_cmd_sp; + } + + CommandObjectScriptingObjectParsed(CommandInterpreter &interpreter, + std::string name, + StructuredData::GenericSP cmd_obj_sp, + ScriptedCommandSynchronicity synch) + : CommandObjectParsed(interpreter, name.c_str()), + m_cmd_obj_sp(cmd_obj_sp), m_synchro(synch), + m_options(interpreter, cmd_obj_sp), m_fetched_help_short(false), + m_fetched_help_long(false) { + StreamString stream; + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + if (!scripter) { + m_options_error.SetErrorString("No script interpreter"); + return; + } + + // Set the flags: + GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); + + // Now set up the options definitions from the options: + StructuredData::ObjectSP options_object_sp + = scripter->GetOptionsForCommandObject(cmd_obj_sp); + // It's okay not to have an options dict. + if (options_object_sp) { + // The options come as a dictionary of dictionaries. The key of the + // outer dict is the long option name (since that's required). The + // value holds all the other option specification bits. + StructuredData::Dictionary *options_dict + = options_object_sp->GetAsDictionary(); + // but if it exists, it has to be an array. + if (options_dict) { + m_options_error = m_options.SetOptionsFromArray(*(options_dict)); + // If we got an error don't bother with the arguments... + if (m_options_error.Fail()) + return; + } else { + m_options_error.SetErrorString("Options array not an array"); + return; + } + } + // Then fetch the args. Since the arguments can have usage masks you need + // an array of arrays. + StructuredData::ObjectSP args_object_sp + = scripter->GetArgumentsForCommandObject(cmd_obj_sp); + if (args_object_sp) { + StructuredData::Array *args_array = args_object_sp->GetAsArray(); + if (!args_array) { + m_args_error.SetErrorString("Argument specification is not an array"); + return; + } + size_t counter = 0; + + // This is the Array::ForEach function that handles the + // CommandArgumentEntry arrays one by one: + auto arg_array_adder = [this, &counter] (StructuredData::Object *object) + -> bool { + // This is the Array::ForEach function to add argument entries: + CommandArgumentEntry this_entry; + size_t elem_counter = 0; + auto args_adder = [this, counter, &elem_counter, &this_entry] + (StructuredData::Object *object) -> bool { + // The arguments definition has three fields, the argument type, the + // repeat and the usage mask. + CommandArgumentType arg_type = eArgTypeNone; + ArgumentRepetitionType arg_repetition = eArgRepeatOptional; + uint32_t arg_opt_set_association; + + auto report_error = [this, elem_counter, counter] + (const char *err_txt) -> bool { + m_args_error.SetErrorStringWithFormatv("Element {0} of arguments " + "list element {1}: %s.", elem_counter, counter, err_txt); + return false; + }; + + StructuredData::Dictionary *arg_dict = object->GetAsDictionary(); + if (!arg_dict) { + report_error("is not a dictionary."); + return false; + } + // Argument Type: + StructuredData::ObjectSP obj_sp + = arg_dict->GetValueForKey("arg_type"); + if (obj_sp) { + StructuredData::UnsignedInteger *uint_val + = obj_sp->GetAsUnsignedInteger(); + if (!uint_val) { + report_error("value type must be an unsigned integer"); + return false; + } + uint64_t arg_type_int = uint_val->GetValue(); + if (arg_type_int >= eArgTypeLastArg) { + report_error("value type beyond ArgumentRepetitionType bounds"); + return false; + } + arg_type = (CommandArgumentType) arg_type_int; + } + // Repeat Value: + obj_sp = arg_dict->GetValueForKey("repeat"); + std::optional<ArgumentRepetitionType> repeat; + if (obj_sp) { + llvm::StringRef repeat_str = obj_sp->GetStringValue(); + if (repeat_str.empty()) { + report_error("repeat value is empty"); + return false; + } + repeat = ArgRepetitionFromString(repeat_str); + if (!repeat) { + report_error("invalid repeat value"); + return false; + } + arg_repetition = *repeat; + } + + // Usage Mask: + obj_sp = arg_dict->GetValueForKey("groups"); + m_args_error = CommandOptions::ParseUsageMaskFromArray(obj_sp, + counter, arg_opt_set_association); + this_entry.emplace_back(arg_type, arg_repetition, + arg_opt_set_association); + elem_counter++; + return true; + }; + StructuredData::Array *args_array = object->GetAsArray(); + if (!args_array) { + m_args_error.SetErrorStringWithFormatv("Argument definition element " + "{0} is not an array", counter); + } + + args_array->ForEach(args_adder); + if (m_args_error.Fail()) + return false; + if (this_entry.empty()) { + m_args_error.SetErrorStringWithFormatv("Argument definition element " + "{0} is empty", counter); + return false; + } + m_arguments.push_back(this_entry); + counter++; + return true; + }; // end of arg_array_adder + // Here we actually parse the args definition: + args_array->ForEach(arg_array_adder); + } + } + + ~CommandObjectScriptingObjectParsed() override = default; + + Status GetOptionsError() { return m_options_error; } + Status GetArgsError() { return m_args_error; } + bool WantsCompletion() override { return true; } + + bool IsRemovable() const override { return true; } + + ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } + + std::optional<std::string> GetRepeatCommand(Args &args, + uint32_t index) override { + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + if (!scripter) + return std::nullopt; + + return scripter->GetRepeatCommandForScriptedCommand(m_cmd_obj_sp, args); + } + + llvm::StringRef GetHelp() override { + if (m_fetched_help_short) + return CommandObjectParsed::GetHelp(); + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + if (!scripter) + return CommandObjectParsed::GetHelp(); + std::string docstring; + m_fetched_help_short = + scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); + if (!docstring.empty()) + SetHelp(docstring); + + return CommandObjectParsed::GetHelp(); + } + + llvm::StringRef GetHelpLong() override { + if (m_fetched_help_long) + return CommandObjectParsed::GetHelpLong(); + + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + if (!scripter) + return CommandObjectParsed::GetHelpLong(); + + std::string docstring; + m_fetched_help_long = + scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); + if (!docstring.empty()) + SetHelpLong(docstring); + return CommandObjectParsed::GetHelpLong(); + } + + Options *GetOptions() override { + // CommandObjectParsed requires that a command with no options return + // nullptr. + if (m_options.GetNumOptions() == 0) + return nullptr; + return &m_options; + } + +protected: + void DoExecute(Args &args, + CommandReturnObject &result) override { + ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); + + Status error; + + result.SetStatus(eReturnStatusInvalid); + + if (!scripter || + !scripter->RunScriptBasedParsedCommand(m_cmd_obj_sp, args, + m_synchro, result, error, m_exe_ctx)) { + result.AppendError(error.AsCString()); + } else { + // Don't change the status if the command already set it... + if (result.GetStatus() == eReturnStatusInvalid) { + if (result.GetOutputData().empty()) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + } + } + } + +private: + StructuredData::GenericSP m_cmd_obj_sp; + ScriptedCommandSynchronicity m_synchro; + CommandOptions m_options; + Status m_options_error; + Status m_args_error; + bool m_fetched_help_short : 1; + bool m_fetched_help_long : 1; +}; + +std::unordered_set<std::string> + CommandObjectScriptingObjectParsed::CommandOptions::g_string_storer; + // CommandObjectCommandsScriptImport #define LLDB_OPTIONS_script_import #include "CommandOptions.inc" @@ -1253,30 +1932,11 @@ public: CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "command script import", "Import a scripting module in LLDB.", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeFilename; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeFilename, eArgRepeatPlus); } ~CommandObjectCommandsScriptImport() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - Options *GetOptions() override { return &m_options; } protected: @@ -1382,20 +2042,7 @@ public: "command, and the last element will be the new " "command name."), IOHandlerDelegateMultiline("DONE") { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // This is one or more command names, which form the path to the command - // you want to add. - cmd_arg.arg_type = eArgTypeCommand; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); } ~CommandObjectCommandsScriptAdd() override = default; @@ -1437,6 +2084,9 @@ protected: case 'o': m_overwrite_lazy = eLazyBoolYes; break; + case 'p': + m_parsed_command = true; + break; case 's': m_synchronicity = (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( @@ -1472,6 +2122,7 @@ protected: m_completion_type = eNoCompletion; m_overwrite_lazy = eLazyBoolCalculate; m_synchronicity = eScriptedCommandSynchronicitySynchronous; + m_parsed_command = false; } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { @@ -1487,6 +2138,7 @@ protected: ScriptedCommandSynchronicity m_synchronicity = eScriptedCommandSynchronicitySynchronous; CompletionType m_completion_type = eNoCompletion; + bool m_parsed_command = false; }; void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -1626,10 +2278,16 @@ protected: "'{0}'", m_options.m_class_name); return; } - - new_cmd_sp.reset(new CommandObjectScriptingObject( - m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, - m_completion_type)); + + if (m_options.m_parsed_command) { + new_cmd_sp = CommandObjectScriptingObjectParsed::Create(m_interpreter, + m_cmd_name, cmd_obj_sp, m_synchronicity, result); + if (!result.Succeeded()) + return; + } else + new_cmd_sp.reset(new CommandObjectScriptingObjectRaw( + m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, + m_completion_type)); } // Assume we're going to succeed... @@ -1644,8 +2302,9 @@ protected: llvm::Error llvm_error = m_container->LoadUserSubcommand(m_cmd_name, new_cmd_sp, m_overwrite); if (llvm_error) - result.AppendErrorWithFormat("cannot add command: %s", - llvm::toString(std::move(llvm_error)).c_str()); + result.AppendErrorWithFormat( + "cannot add command: %s", + llvm::toString(std::move(llvm_error)).c_str()); } } @@ -1704,20 +2363,7 @@ public: interpreter, "command script delete", "Delete a scripted command by specifying the path to the command.", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // This is a list of command names forming the path to the command - // to be deleted. - cmd_arg.arg_type = eArgTypeCommand; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); } ~CommandObjectCommandsScriptDelete() override = default; @@ -1788,12 +2434,13 @@ protected: return; } const char *leaf_cmd = command[num_args - 1].c_str(); - llvm::Error llvm_error = container->RemoveUserSubcommand(leaf_cmd, - /* multiword not okay */ false); + llvm::Error llvm_error = + container->RemoveUserSubcommand(leaf_cmd, + /* multiword not okay */ false); if (llvm_error) { - result.AppendErrorWithFormat("could not delete command '%s': %s", - leaf_cmd, - llvm::toString(std::move(llvm_error)).c_str()); + result.AppendErrorWithFormat( + "could not delete command '%s': %s", leaf_cmd, + llvm::toString(std::move(llvm_error)).c_str()); return; } @@ -1852,20 +2499,7 @@ public: "Add a container command to lldb. Adding to built-" "in container commands is not allowed.", "command container add [[path1]...] container-name") { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // This is one or more command names, which form the path to the command - // you want to add. - cmd_arg.arg_type = eArgTypeCommand; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); } ~CommandObjectCommandsContainerAdd() override = default; @@ -1993,20 +2627,7 @@ public: "Delete a container command previously added to " "lldb.", "command container delete [[path1] ...] container-cmd") { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // This is one or more command names, which form the path to the command - // you want to add. - cmd_arg.arg_type = eArgTypeCommand; - cmd_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeCommand, eArgRepeatPlus); } ~CommandObjectCommandsContainerDelete() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp index 695f3d7931cd..b7cd955e0020 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -23,7 +23,6 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/FormatVariadic.h" #include <regex> @@ -37,8 +36,7 @@ CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter) "dwim-print [<variable-name> | <expression>]", eCommandProcessMustBePaused | eCommandTryTargetAPILock) { - CommandArgumentData var_name_arg(eArgTypeVarName, eArgRepeatPlain); - m_arguments.push_back({var_name_arg}); + AddSimpleArgumentList(eArgTypeVarName); m_option_group.Append(&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | @@ -52,12 +50,6 @@ CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter) Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; } -void CommandObjectDWIMPrint::HandleArgumentCompletion( - CompletionRequest &request, OptionElementVector &opt_element_vector) { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eVariablePathCompletion, request, nullptr); -} - void CommandObjectDWIMPrint::DoExecute(StringRef command, CommandReturnObject &result) { m_option_group.NotifyOptionParsingStarting(&m_exe_ctx); @@ -101,10 +93,10 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, StackFrame *frame = m_exe_ctx.GetFramePtr(); - // Either Swift was explicitly specified, or the frame is Swift. + // Either the language was explicitly specified, or we check the frame. lldb::LanguageType language = m_expr_options.language; if (language == lldb::eLanguageTypeUnknown && frame) - language = frame->GuessLanguage(); + language = frame->GuessLanguage().AsLanguageType(); // Add a hint if object description was requested, but no description // function was implemented. @@ -137,6 +129,28 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, } }; + // Dump `valobj` according to whether `po` was requested or not. + auto dump_val_object = [&](ValueObject &valobj) { + if (is_po) { + StreamString temp_result_stream; + if (llvm::Error error = valobj.Dump(temp_result_stream, dump_options)) { + result.AppendError(toString(std::move(error))); + return; + } + llvm::StringRef output = temp_result_stream.GetString(); + maybe_add_hint(output); + result.GetOutputStream() << output; + } else { + llvm::Error error = + valobj.Dump(result.GetOutputStream(), dump_options); + if (error) { + result.AppendError(toString(std::move(error))); + return; + } + } + result.SetStatus(eReturnStatusSuccessFinishResult); + }; + // First, try `expr` as the name of a frame variable. if (frame) { auto valobj_sp = frame->FindVariable(ConstString(expr)); @@ -154,21 +168,21 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, flags, expr); } - if (is_po) { - StreamString temp_result_stream; - valobj_sp->Dump(temp_result_stream, dump_options); - llvm::StringRef output = temp_result_stream.GetString(); - maybe_add_hint(output); - result.GetOutputStream() << output; - } else { - valobj_sp->Dump(result.GetOutputStream(), dump_options); - } - result.SetStatus(eReturnStatusSuccessFinishResult); + dump_val_object(*valobj_sp); return; } } - // Second, also lastly, try `expr` as a source expression to evaluate. + // Second, try `expr` as a persistent variable. + if (expr.starts_with("$")) + if (auto *state = target.GetPersistentExpressionStateForLanguage(language)) + if (auto var_sp = state->GetVariable(expr)) + if (auto valobj_sp = var_sp->GetValueObject()) { + dump_val_object(*valobj_sp); + return; + } + + // Third, and lastly, try `expr` as a source expression to evaluate. { auto *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); ValueObjectSP valobj_sp; @@ -185,43 +199,36 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, error_stream << " " << fixed_expression << "\n"; } - if (expr_result == eExpressionCompleted) { - if (verbosity != eDWIMPrintVerbosityNone) { - StringRef flags; - if (args.HasArgs()) - flags = args.GetArgStringWithDelimiter(); - result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags, - expr); - } - - if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) { - if (is_po) { - StreamString temp_result_stream; - valobj_sp->Dump(temp_result_stream, dump_options); - llvm::StringRef output = temp_result_stream.GetString(); - maybe_add_hint(output); - result.GetOutputStream() << output; - } else { - valobj_sp->Dump(result.GetOutputStream(), dump_options); - } - } - - if (suppress_result) - if (auto result_var_sp = - target.GetPersistentVariable(valobj_sp->GetName())) { - auto language = valobj_sp->GetPreferredDisplayLanguage(); - if (auto *persistent_state = - target.GetPersistentExpressionStateForLanguage(language)) - persistent_state->RemovePersistentVariable(result_var_sp); - } - - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { + // If the expression failed, return an error. + if (expr_result != eExpressionCompleted) { if (valobj_sp) result.SetError(valobj_sp->GetError()); else result.AppendErrorWithFormatv( "unknown error evaluating expression `{0}`", expr); + return; + } + + if (verbosity != eDWIMPrintVerbosityNone) { + StringRef flags; + if (args.HasArgs()) + flags = args.GetArgStringWithDelimiter(); + result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags, + expr); } + + if (valobj_sp->GetError().GetError() != UserExpression::kNoResult) + dump_val_object(*valobj_sp); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + + if (suppress_result) + if (auto result_var_sp = + target.GetPersistentVariable(valobj_sp->GetName())) { + auto language = valobj_sp->GetPreferredDisplayLanguage(); + if (auto *persistent_state = + target.GetPersistentExpressionStateForLanguage(language)) + persistent_state->RemovePersistentVariable(result_var_sp); + } } } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.h index d868f8964c2a..01ba9c225e33 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.h +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectDWIMPrint.h @@ -39,10 +39,6 @@ public: bool WantsCompletion() override { return true; } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override; - private: void DoExecute(llvm::StringRef command, CommandReturnObject &result) override; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp index 3a2dc11e1e71..eb76753d98ef 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectExpression.cpp @@ -311,19 +311,7 @@ Examples: expr unsigned int $foo = 5 expr char c[] = \"foo\"; c[0])"); - CommandArgumentEntry arg; - CommandArgumentData expression_arg; - - // Define the first (and only) variant of this arg. - expression_arg.arg_type = eArgTypeExpression; - expression_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument - // entry. - arg.push_back(expression_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeExpression); // Add the "--format" and "--gdb-format" m_option_group.Append(&m_format_options, @@ -473,7 +461,11 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, options.SetVariableFormatDisplayLanguage( result_valobj_sp->GetPreferredDisplayLanguage()); - result_valobj_sp->Dump(output_stream, options); + if (llvm::Error error = + result_valobj_sp->Dump(output_stream, options)) { + result.AppendError(toString(std::move(error))); + return false; + } if (suppress_result) if (auto result_var_sp = diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp index 17a7e858b24e..3f4178c1a959 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectFrame.cpp @@ -113,19 +113,7 @@ public: eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeFrameIndex; - index_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFrameIndex, eArgRepeatOptional); } ~CommandObjectFrameDiagnose() override = default; @@ -177,9 +165,13 @@ protected: DumpValueObjectOptions options; options.SetDeclPrintingHelper(helper); - ValueObjectPrinter printer(valobj_sp.get(), &result.GetOutputStream(), + // We've already handled the case where the value object sp is null, so + // this is just to make sure future changes don't skip that: + assert(valobj_sp.get() && "Must have a valid ValueObject to print"); + ValueObjectPrinter printer(*valobj_sp, &result.GetOutputStream(), options); - printer.PrintValueObject(); + if (llvm::Error error = printer.PrintValueObject()) + result.AppendError(toString(std::move(error))); } CommandOptions m_options; @@ -266,33 +258,11 @@ public: eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeFrameIndex; - index_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFrameIndex, eArgRepeatOptional); } ~CommandObjectFrameSelect() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() != 0) - return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eFrameIndexCompletion, request, nullptr); - } - Options *GetOptions() override { return &m_options; } protected: @@ -416,19 +386,7 @@ However, 'frame variable' is more efficient, since it uses debug information and memory reads directly, rather than parsing and evaluating an expression, which may even involve JITing and running code in the target program.)"); - CommandArgumentEntry arg; - CommandArgumentData var_name_arg; - - // Define the first (and only) variant of this arg. - var_name_arg.arg_type = eArgTypeVarName; - var_name_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(var_name_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeVarName, eArgRepeatStar); m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_option_format, @@ -443,15 +401,6 @@ may even involve JITing and running code in the target program.)"); Options *GetOptions() override { return &m_option_group; } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - // Arguments are the standard source file completer. - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eVariablePathCompletion, request, - nullptr); - } - protected: llvm::StringRef GetScopeString(VariableSP var_sp) { if (!var_sp) @@ -607,7 +556,9 @@ protected: show_module)) s.PutCString(": "); } - valobj_sp->Dump(result.GetOutputStream(), options); + auto &strm = result.GetOutputStream(); + if (llvm::Error error = valobj_sp->Dump(strm, options)) + result.AppendError(toString(std::move(error))); } } } else { @@ -649,7 +600,8 @@ protected: Stream &output_stream = result.GetOutputStream(); options.SetRootValueObjectName( valobj_sp->GetParent() ? entry.c_str() : nullptr); - valobj_sp->Dump(output_stream, options); + if (llvm::Error error = valobj_sp->Dump(output_stream, options)) + result.AppendError(toString(std::move(error))); } else { if (auto error_cstr = error.AsCString(nullptr)) result.AppendError(error_cstr); @@ -700,7 +652,9 @@ protected: valobj_sp->GetPreferredDisplayLanguage()); options.SetRootValueObjectName( var_sp ? var_sp->GetName().AsCString() : nullptr); - valobj_sp->Dump(result.GetOutputStream(), options); + if (llvm::Error error = + valobj_sp->Dump(result.GetOutputStream(), options)) + result.AppendError(toString(std::move(error))); } } } @@ -721,7 +675,9 @@ protected: options.SetVariableFormatDisplayLanguage( rec_value_sp->GetPreferredDisplayLanguage()); options.SetRootValueObjectName(rec_value_sp->GetName().AsCString()); - rec_value_sp->Dump(result.GetOutputStream(), options); + if (llvm::Error error = + rec_value_sp->Dump(result.GetOutputStream(), options)) + result.AppendError(toString(std::move(error))); } } } @@ -955,8 +911,7 @@ public: : CommandObjectParsed(interpreter, "frame recognizer delete", "Delete an existing frame recognizer by id.", nullptr) { - CommandArgumentData thread_arg{eArgTypeRecognizerID, eArgRepeatPlain}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeRecognizerID); } ~CommandObjectFrameRecognizerDelete() override = default; @@ -1081,19 +1036,7 @@ public: interpreter, "frame recognizer info", "Show which frame recognizer is applied a stack frame (if any).", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeFrameIndex; - index_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFrameIndex); } ~CommandObjectFrameRecognizerInfo() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp index ddb006e52d2c..f1dbd03fe97c 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectHelp.cpp @@ -48,20 +48,9 @@ CommandObjectHelp::CommandObjectHelp(CommandInterpreter &interpreter) "commands, or give details " "about a specific command.", "help [<cmd-name>]") { - CommandArgumentEntry arg; - CommandArgumentData command_arg; - // A list of command names forming a path to the command we want help on. // No names is allowed - in which case we dump the top-level help. - command_arg.arg_type = eArgTypeCommand; - command_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument - // entry. - arg.push_back(command_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeCommand, eArgRepeatStar); } CommandObjectHelp::~CommandObjectHelp() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp index 6bfbf98078e6..48dfd9456a66 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectLog.cpp @@ -288,19 +288,7 @@ public: "List the log categories for one or more log " "channels. If none specified, lists them all.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData channel_arg; - - // Define the first (and only) variant of this arg. - channel_arg.arg_type = eArgTypeLogChannel; - channel_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(channel_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeLogChannel, eArgRepeatStar); } ~CommandObjectLogList() override = default; @@ -335,19 +323,7 @@ public: CommandObjectLogDump(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "log dump", "dump circular buffer logs", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData channel_arg; - - // Define the first (and only) variant of this arg. - channel_arg.arg_type = eArgTypeLogChannel; - channel_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(channel_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeLogChannel); } ~CommandObjectLogDump() override = default; @@ -444,19 +420,7 @@ public: : CommandObjectParsed(interpreter, "log timers enable", "enable LLDB internal performance timers", "log timers enable <depth>") { - CommandArgumentEntry arg; - CommandArgumentData depth_arg; - - // Define the first (and only) variant of this arg. - depth_arg.arg_type = eArgTypeCount; - depth_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(depth_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeCount, eArgRepeatOptional); } ~CommandObjectLogTimerEnable() override = default; @@ -559,19 +523,7 @@ public: : CommandObjectParsed(interpreter, "log timers increment", "increment LLDB internal performance timers", "log timers increment <bool>") { - CommandArgumentEntry arg; - CommandArgumentData bool_arg; - - // Define the first (and only) variant of this arg. - bool_arg.arg_type = eArgTypeBoolean; - bool_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(bool_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeBoolean); } ~CommandObjectLogTimerIncrement() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp index b78a0492cca5..137b1ad98107 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp @@ -815,7 +815,10 @@ protected: DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( eLanguageRuntimeDescriptionDisplayVerbosityFull, format)); - valobj_sp->Dump(*output_stream_p, options); + if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) { + result.AppendError(toString(std::move(error))); + return; + } } else { result.AppendErrorWithFormat( "failed to create a value object for: (%s) %s\n", @@ -977,35 +980,6 @@ public: Options *GetOptions() override { return &m_option_group; } protected: - class ProcessMemoryIterator { - public: - ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base) - : m_process_sp(process_sp), m_base_addr(base) { - lldbassert(process_sp.get() != nullptr); - } - - bool IsValid() { return m_is_valid; } - - uint8_t operator[](lldb::addr_t offset) { - if (!IsValid()) - return 0; - - uint8_t retval = 0; - Status error; - if (0 == - m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) { - m_is_valid = false; - return 0; - } - - return retval; - } - - private: - ProcessSP m_process_sp; - lldb::addr_t m_base_addr; - bool m_is_valid = true; - }; void DoExecute(Args &command, CommandReturnObject &result) override { // No need to check "process" for validity as eCommandRequiresProcess // ensures it is valid @@ -1106,8 +1080,8 @@ protected: found_location = low_addr; bool ever_found = false; while (count) { - found_location = FastSearch(found_location, high_addr, buffer.GetBytes(), - buffer.GetByteSize()); + found_location = process->FindInMemory( + found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize()); if (found_location == LLDB_INVALID_ADDRESS) { if (!ever_found) { result.AppendMessage("data not found within the range.\n"); @@ -1144,34 +1118,6 @@ protected: result.SetStatus(lldb::eReturnStatusSuccessFinishResult); } - lldb::addr_t FastSearch(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer, - size_t buffer_size) { - const size_t region_size = high - low; - - if (region_size < buffer_size) - return LLDB_INVALID_ADDRESS; - - std::vector<size_t> bad_char_heuristic(256, buffer_size); - ProcessSP process_sp = m_exe_ctx.GetProcessSP(); - ProcessMemoryIterator iterator(process_sp, low); - - for (size_t idx = 0; idx < buffer_size - 1; idx++) { - decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx]; - bad_char_heuristic[bcu_idx] = buffer_size - idx - 1; - } - for (size_t s = 0; s <= (region_size - buffer_size);) { - int64_t j = buffer_size - 1; - while (j >= 0 && buffer[j] == iterator[s + j]) - j--; - if (j < 0) - return low + s; - else - s += bad_char_heuristic[iterator[s + buffer_size - 1]]; - } - - return LLDB_INVALID_ADDRESS; - } - OptionGroupOptions m_option_group; OptionGroupFindMemory m_memory_options; OptionGroupMemoryTag m_memory_tag_options; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp index 790f1dbb4753..5b18f2b60e92 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlatform.cpp @@ -155,8 +155,7 @@ public: { m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1); m_option_group.Finalize(); - CommandArgumentData platform_arg{eArgTypePlatform, eArgRepeatPlain}; - m_arguments.push_back({platform_arg}); + AddSimpleArgumentList(eArgTypePlatform); } ~CommandObjectPlatformSelect() override = default; @@ -276,8 +275,7 @@ public: interpreter, "platform connect", "Select the current platform by providing a connection URL.", "platform connect <connect-url>", 0) { - CommandArgumentData platform_arg{eArgTypeConnectURL, eArgRepeatPlain}; - m_arguments.push_back({platform_arg}); + AddSimpleArgumentList(eArgTypeConnectURL); } ~CommandObjectPlatformConnect() override = default; @@ -418,8 +416,7 @@ public: : CommandObjectParsed(interpreter, "platform mkdir", "Make a new directory on the remote end.", nullptr, 0) { - CommandArgumentData thread_arg{eArgTypePath, eArgRepeatPlain}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeRemotePath); } ~CommandObjectPlatformMkDir() override = default; @@ -467,21 +464,11 @@ public: CommandObjectPlatformFOpen(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "platform file open", "Open a file on the remote end.", nullptr, 0) { - CommandArgumentData path_arg{eArgTypePath, eArgRepeatPlain}; - m_arguments.push_back({path_arg}); + AddSimpleArgumentList(eArgTypeRemotePath); } ~CommandObjectPlatformFOpen() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() == 0) - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request, - nullptr); - } - void DoExecute(Args &args, CommandReturnObject &result) override { PlatformSP platform_sp( GetDebugger().GetPlatformList().GetSelectedPlatform()); @@ -530,8 +517,7 @@ public: CommandObjectPlatformFClose(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "platform file close", "Close a file on the remote end.", nullptr, 0) { - CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({path_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectPlatformFClose() override = default; @@ -573,8 +559,7 @@ public: : CommandObjectParsed(interpreter, "platform file read", "Read data from a file on the remote end.", nullptr, 0) { - CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({path_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectPlatformFRead() override = default; @@ -668,8 +653,7 @@ public: : CommandObjectParsed(interpreter, "platform file write", "Write data to a file on the remote end.", nullptr, 0) { - CommandArgumentData path_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({path_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectPlatformFWrite() override = default; @@ -795,7 +779,7 @@ public: CommandArgumentData file_arg_remote, file_arg_host; // Define the first (and only) variant of this arg. - file_arg_remote.arg_type = eArgTypeFilename; + file_arg_remote.arg_type = eArgTypeRemoteFilename; file_arg_remote.arg_repetition = eArgRepeatPlain; // There is only one variant this argument could be; put it into the // argument entry. @@ -872,33 +856,11 @@ public: Get the file size from the remote end with path /the/remote/file/path.)"); - CommandArgumentEntry arg1; - CommandArgumentData file_arg_remote; - - // Define the first (and only) variant of this arg. - file_arg_remote.arg_type = eArgTypeFilename; - file_arg_remote.arg_repetition = eArgRepeatPlain; - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(file_arg_remote); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeRemoteFilename); } ~CommandObjectPlatformGetSize() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() != 0) - return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request, - nullptr); - } - void DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 1) { @@ -942,33 +904,11 @@ public: Get the file permissions from the remote end with path /the/remote/file/path.)"); - CommandArgumentEntry arg1; - CommandArgumentData file_arg_remote; - - // Define the first (and only) variant of this arg. - file_arg_remote.arg_type = eArgTypeFilename; - file_arg_remote.arg_repetition = eArgRepeatPlain; - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(file_arg_remote); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeRemoteFilename); } ~CommandObjectPlatformGetPermissions() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() != 0) - return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request, - nullptr); - } - void DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 1) { @@ -1011,33 +951,11 @@ public: Check if /the/remote/file/path exists on the remote end.)"); - CommandArgumentEntry arg1; - CommandArgumentData file_arg_remote; - - // Define the first (and only) variant of this arg. - file_arg_remote.arg_type = eArgTypeFilename; - file_arg_remote.arg_repetition = eArgRepeatPlain; - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(file_arg_remote); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeRemoteFilename); } ~CommandObjectPlatformFileExists() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() != 0) - return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request, - nullptr); - } - void DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 1) { @@ -1080,7 +998,7 @@ public: Omitting the destination places the file in the platform working directory.)"); CommandArgumentData source_arg{eArgTypePath, eArgRepeatPlain}; - CommandArgumentData path_arg{eArgTypePath, eArgRepeatOptional}; + CommandArgumentData path_arg{eArgTypeRemotePath, eArgRepeatOptional}; m_arguments.push_back({source_arg}); m_arguments.push_back({path_arg}); } @@ -1135,8 +1053,17 @@ public: m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_ALL); m_all_options.Finalize(); - CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar}; - m_arguments.push_back({run_arg_arg}); + AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatStar); + } + + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + // I didn't make a type for RemoteRunArgs, but since we're going to run + // this on the remote system we should use the remote completer. + lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), lldb::eRemoteDiskFileCompletion, request, + nullptr); } ~CommandObjectPlatformProcessLaunch() override = default; @@ -1535,30 +1462,11 @@ public: interpreter, "platform process info", "Get detailed information for one or more process by process ID.", "platform process info <pid> [<pid> <pid> ...]", 0) { - CommandArgumentEntry arg; - CommandArgumentData pid_args; - - // Define the first (and only) variant of this arg. - pid_args.arg_type = eArgTypePid; - pid_args.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(pid_args); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypePid, eArgRepeatStar); } ~CommandObjectPlatformProcessInfo() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eProcessIDCompletion, request, nullptr); - } - protected: void DoExecute(Args &args, CommandReturnObject &result) override { Target *target = GetDebugger().GetSelectedTarget().get(); @@ -1760,8 +1668,7 @@ public: : CommandObjectRaw(interpreter, "platform shell", "Run a shell command on the current platform.", "platform shell <shell-command>", 0) { - CommandArgumentData thread_arg{eArgTypeNone, eArgRepeatStar}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar); } ~CommandObjectPlatformShell() override = default; @@ -1850,7 +1757,7 @@ public: "Install a target (bundle or executable file) to the remote end.", "platform target-install <local-thing> <remote-sandbox>", 0) { CommandArgumentData local_arg{eArgTypePath, eArgRepeatPlain}; - CommandArgumentData remote_arg{eArgTypePath, eArgRepeatPlain}; + CommandArgumentData remote_arg{eArgTypeRemotePath, eArgRepeatPlain}; m_arguments.push_back({local_arg}); m_arguments.push_back({remote_arg}); } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlugin.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlugin.cpp index f22885144b09..f3108b8a768d 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectPlugin.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectPlugin.cpp @@ -19,30 +19,11 @@ public: : CommandObjectParsed(interpreter, "plugin load", "Import a dylib that implements an LLDB plugin.", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData cmd_arg; - - // Define the first (and only) variant of this arg. - cmd_arg.arg_type = eArgTypeFilename; - cmd_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(cmd_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeFilename); } ~CommandObjectPluginLoad() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { size_t argc = command.GetArgumentCount(); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp index 6dc7648f872d..50695af55693 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectProcess.cpp @@ -126,31 +126,11 @@ public: LLDB_OPT_SET_ALL); m_all_options.Finalize(); - CommandArgumentEntry arg; - CommandArgumentData run_args_arg; - - // Define the first (and only) variant of this arg. - run_args_arg.arg_type = eArgTypeRunArgs; - run_args_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(run_args_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatOptional); } ~CommandObjectProcessLaunch() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - Options *GetOptions() override { return &m_all_options; } std::optional<std::string> GetRepeatCommand(Args ¤t_command_args, @@ -646,9 +626,7 @@ protected: for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) { BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(loc_idx); tmp_id.SetBreakpointLocationID(loc_idx); - size_t position = 0; - if (!with_locs.FindBreakpointID(tmp_id, &position) - && loc_sp->IsEnabled()) { + if (!with_locs.Contains(tmp_id) && loc_sp->IsEnabled()) { locs_disabled.push_back(tmp_id); loc_sp->SetEnabled(false); } @@ -880,8 +858,7 @@ public: : CommandObjectParsed(interpreter, "process connect", "Connect to a remote debug service.", "process connect <remote-url>", 0) { - CommandArgumentData connect_arg{eArgTypeConnectURL, eArgRepeatPlain}; - m_arguments.push_back({connect_arg}); + AddSimpleArgumentList(eArgTypeConnectURL); } ~CommandObjectProcessConnect() override = default; @@ -973,11 +950,13 @@ public: ExecutionContext *execution_context) override { Status error; const int short_option = m_getopt_table[option_idx].val; + ArchSpec arch = + execution_context->GetProcessPtr()->GetSystemArchitecture(); switch (short_option) { case 'i': do_install = true; if (!option_arg.empty()) - install_path.SetFile(option_arg, FileSpec::Style::native); + install_path.SetFile(option_arg, arch.GetTriple()); break; default: llvm_unreachable("Unimplemented option"); @@ -1006,8 +985,7 @@ public: eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlus}; - m_arguments.push_back({file_arg}); + AddSimpleArgumentList(eArgTypePath, eArgRepeatPlus); } ~CommandObjectProcessLoad() override = default; @@ -1017,9 +995,7 @@ public: OptionElementVector &opt_element_vector) override { if (!m_exe_ctx.HasProcessScope()) return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } Options *GetOptions() override { return &m_options; } @@ -1082,8 +1058,7 @@ public: "process unload <index>", eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentData load_idx_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({load_idx_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectProcessUnload() override = default; @@ -1143,19 +1118,7 @@ public: interpreter, "process signal", "Send a UNIX signal to the current target process.", nullptr, eCommandRequiresProcess | eCommandTryTargetAPILock) { - CommandArgumentEntry arg; - CommandArgumentData signal_arg; - - // Define the first (and only) variant of this arg. - signal_arg.arg_type = eArgTypeUnixSignal; - signal_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(signal_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeUnixSignal); } ~CommandObjectProcessSignal() override = default; @@ -1286,21 +1249,13 @@ public: "process save-core [-s corefile-style -p plugin-name] FILE", eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched) { - CommandArgumentData file_arg{eArgTypePath, eArgRepeatPlain}; - m_arguments.push_back({file_arg}); + AddSimpleArgumentList(eArgTypePath); } ~CommandObjectProcessSaveCore() override = default; Options *GetOptions() override { return &m_options; } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - class CommandOptions : public Options { public: CommandOptions() = default; @@ -1318,13 +1273,13 @@ public: switch (short_option) { case 'p': - m_requested_plugin_name = option_arg.str(); + error = m_core_dump_options.SetPluginName(option_arg.data()); break; case 's': - m_requested_save_core_style = + m_core_dump_options.SetStyle( (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum( option_arg, GetDefinitions()[option_idx].enum_values, - eSaveCoreUnspecified, error); + eSaveCoreUnspecified, error)); break; default: llvm_unreachable("Unimplemented option"); @@ -1334,13 +1289,11 @@ public: } void OptionParsingStarting(ExecutionContext *execution_context) override { - m_requested_save_core_style = eSaveCoreUnspecified; - m_requested_plugin_name.clear(); + m_core_dump_options.Clear(); } // Instance variables to hold the values for command options. - SaveCoreStyle m_requested_save_core_style = eSaveCoreUnspecified; - std::string m_requested_plugin_name; + SaveCoreOptions m_core_dump_options; }; protected: @@ -1350,13 +1303,14 @@ protected: if (command.GetArgumentCount() == 1) { FileSpec output_file(command.GetArgumentAtIndex(0)); FileSystem::Instance().Resolve(output_file); - SaveCoreStyle corefile_style = m_options.m_requested_save_core_style; - Status error = - PluginManager::SaveCore(process_sp, output_file, corefile_style, - m_options.m_requested_plugin_name); + auto &core_dump_options = m_options.m_core_dump_options; + core_dump_options.SetOutputFile(output_file); + Status error = PluginManager::SaveCore(process_sp, core_dump_options); if (error.Success()) { - if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly || - corefile_style == SaveCoreStyle::eSaveCoreStackOnly) { + if (core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreDirtyOnly || + core_dump_options.GetStyle() == + SaveCoreStyle::eSaveCoreStackOnly) { result.AppendMessageWithFormat( "\nModified-memory or stack-memory only corefile " "created. This corefile may \n" @@ -1455,7 +1409,7 @@ protected: if (m_options.m_verbose) { addr_t code_mask = process->GetCodeAddressMask(); addr_t data_mask = process->GetDataAddressMask(); - if (code_mask != 0) { + if (code_mask != LLDB_INVALID_ADDRESS_MASK) { int bits = std::bitset<64>(~code_mask).count(); result.AppendMessageWithFormat( "Addressable code address mask: 0x%" PRIx64 "\n", code_mask); @@ -1578,41 +1532,13 @@ public: "by passing the -t option." "\nYou can also clear the target modification for a signal" "by passing the -c option"); - CommandArgumentEntry arg; - CommandArgumentData signal_arg; - - signal_arg.arg_type = eArgTypeUnixSignal; - signal_arg.arg_repetition = eArgRepeatStar; - - arg.push_back(signal_arg); - - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeUnixSignal, eArgRepeatStar); } ~CommandObjectProcessHandle() override = default; Options *GetOptions() override { return &m_options; } - bool VerifyCommandOptionValue(const std::string &option, int &real_value) { - bool okay = true; - bool success = false; - bool tmp_value = OptionArgParser::ToBoolean(option, false, &success); - - if (success && tmp_value) - real_value = 1; - else if (success && !tmp_value) - real_value = 0; - else { - // If the value isn't 'true' or 'false', it had better be 0 or 1. - if (!llvm::to_integer(option, real_value)) - real_value = 3; - if (real_value != 0 && real_value != 1) - okay = false; - } - - return okay; - } - void PrintSignalHeader(Stream &str) { str.Printf("NAME PASS STOP NOTIFY\n"); str.Printf("=========== ===== ===== ======\n"); @@ -1668,33 +1594,52 @@ protected: // the user's options. ProcessSP process_sp = target.GetProcessSP(); - int stop_action = -1; // -1 means leave the current setting alone - int pass_action = -1; // -1 means leave the current setting alone - int notify_action = -1; // -1 means leave the current setting alone + std::optional<bool> stop_action = {}; + std::optional<bool> pass_action = {}; + std::optional<bool> notify_action = {}; - if (!m_options.stop.empty() && - !VerifyCommandOptionValue(m_options.stop, stop_action)) { - result.AppendError("Invalid argument for command option --stop; must be " - "true or false.\n"); - return; + if (!m_options.stop.empty()) { + bool success = false; + bool value = OptionArgParser::ToBoolean(m_options.stop, false, &success); + if (!success) { + result.AppendError( + "Invalid argument for command option --stop; must be " + "true or false.\n"); + return; + } + + stop_action = value; } - if (!m_options.notify.empty() && - !VerifyCommandOptionValue(m_options.notify, notify_action)) { - result.AppendError("Invalid argument for command option --notify; must " - "be true or false.\n"); - return; + if (!m_options.pass.empty()) { + bool success = false; + bool value = OptionArgParser::ToBoolean(m_options.pass, false, &success); + if (!success) { + result.AppendError( + "Invalid argument for command option --pass; must be " + "true or false.\n"); + return; + } + pass_action = value; } - if (!m_options.pass.empty() && - !VerifyCommandOptionValue(m_options.pass, pass_action)) { - result.AppendError("Invalid argument for command option --pass; must be " - "true or false.\n"); - return; + if (!m_options.notify.empty()) { + bool success = false; + bool value = + OptionArgParser::ToBoolean(m_options.notify, false, &success); + if (!success) { + result.AppendError("Invalid argument for command option --notify; must " + "be true or false.\n"); + return; + } + notify_action = value; } - bool no_actions = (stop_action == -1 && pass_action == -1 - && notify_action == -1); + if (!m_options.notify.empty() && !notify_action.has_value()) { + } + + bool no_actions = (!stop_action.has_value() && !pass_action.has_value() && + !notify_action.has_value()); if (m_options.only_target_values && !no_actions) { result.AppendError("-t is for reporting, not setting, target values."); return; @@ -1732,16 +1677,14 @@ protected: if (signals_sp) { int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str()); if (signo != LLDB_INVALID_SIGNAL_NUMBER) { - // Casting the actions as bools here should be okay, because - // VerifyCommandOptionValue guarantees the value is either 0 or 1. - if (stop_action != -1) - signals_sp->SetShouldStop(signo, stop_action); - if (pass_action != -1) { - bool suppress = !pass_action; + if (stop_action.has_value()) + signals_sp->SetShouldStop(signo, *stop_action); + if (pass_action.has_value()) { + bool suppress = !*pass_action; signals_sp->SetShouldSuppress(signo, suppress); } - if (notify_action != -1) - signals_sp->SetShouldNotify(signo, notify_action); + if (notify_action.has_value()) + signals_sp->SetShouldNotify(signo, *notify_action); ++num_signals_set; } else { result.AppendErrorWithFormat("Invalid signal name '%s'\n", @@ -1761,21 +1704,15 @@ protected: } num_signals_set = num_args; } - auto set_lazy_bool = [] (int action) -> LazyBool { - LazyBool lazy; - if (action == -1) - lazy = eLazyBoolCalculate; - else if (action) - lazy = eLazyBoolYes; - else - lazy = eLazyBoolNo; - return lazy; + auto set_lazy_bool = [](std::optional<bool> action) -> LazyBool { + if (!action.has_value()) + return eLazyBoolCalculate; + return (*action) ? eLazyBoolYes : eLazyBoolNo; }; // If there were no actions, we're just listing, don't add the dummy: if (!no_actions) - target.AddDummySignal(arg.ref(), - set_lazy_bool(pass_action), + target.AddDummySignal(arg.ref(), set_lazy_bool(pass_action), set_lazy_bool(notify_action), set_lazy_bool(stop_action)); } @@ -1783,18 +1720,19 @@ protected: // No signal specified, if any command options were specified, update ALL // signals. But we can't do this without a process since we don't know // all the possible signals that might be valid for this target. - if (((notify_action != -1) || (stop_action != -1) || (pass_action != -1)) - && process_sp) { + if ((notify_action.has_value() || stop_action.has_value() || + pass_action.has_value()) && + process_sp) { if (m_interpreter.Confirm( "Do you really want to update all the signals?", false)) { int32_t signo = signals_sp->GetFirstSignalNumber(); while (signo != LLDB_INVALID_SIGNAL_NUMBER) { - if (notify_action != -1) - signals_sp->SetShouldNotify(signo, notify_action); - if (stop_action != -1) - signals_sp->SetShouldStop(signo, stop_action); - if (pass_action != -1) { - bool suppress = !pass_action; + if (notify_action.has_value()) + signals_sp->SetShouldNotify(signo, *notify_action); + if (stop_action.has_value()) + signals_sp->SetShouldStop(signo, *stop_action); + if (pass_action.has_value()) { + bool suppress = !*pass_action; signals_sp->SetShouldSuppress(signo, suppress); } signo = signals_sp->GetNextSignalNumber(signo); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp index d7caf1546fb5..8e7830b2afc6 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectQuit.cpp @@ -21,8 +21,7 @@ using namespace lldb_private; CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.", "quit [exit-code]") { - CommandArgumentData exit_code_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({exit_code_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } CommandObjectQuit::~CommandObjectQuit() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp index a4d53e5c8dd5..4e047ccbc10b 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectRegister.cpp @@ -50,19 +50,7 @@ public: {{CommandArgumentType::eArgTypeFormat, "Specify a format to be used for display. If this " "is set, register fields will not be displayed."}}) { - CommandArgumentEntry arg; - CommandArgumentData register_arg; - - // Define the first (and only) variant of this arg. - register_arg.arg_type = eArgTypeRegisterName; - register_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(register_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeRegisterName, eArgRepeatStar); // Add the "--format" m_option_group.Append(&m_format_options, @@ -80,9 +68,7 @@ public: OptionElementVector &opt_element_vector) override { if (!m_exe_ctx.HasProcessScope()) return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } Options *GetOptions() override { return &m_option_group; } @@ -424,13 +410,7 @@ Fields (*) A table of the names and bit positions of the values contained Fields marked with (*) may not always be present. Some information may be different for the same register when connected to different debug servers.)"); - CommandArgumentData register_arg; - register_arg.arg_type = eArgTypeRegisterName; - register_arg.arg_repetition = eArgRepeatPlain; - - CommandArgumentEntry arg1; - arg1.push_back(register_arg); - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeRegisterName); } ~CommandObjectRegisterInfo() override = default; @@ -440,8 +420,7 @@ different for the same register when connected to different debug servers.)"); OptionElementVector &opt_element_vector) override { if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) return; - CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eRegisterCompletion, request, nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } protected: diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp deleted file mode 100644 index 25f25b8e6594..000000000000 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===-- CommandObjectScript.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 "CommandObjectScript.h" -#include "lldb/Core/Debugger.h" -#include "lldb/DataFormatters/DataVisualization.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/OptionParser.h" -#include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/CommandOptionArgumentTable.h" -#include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Interpreter/OptionArgParser.h" -#include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Utility/Args.h" - -using namespace lldb; -using namespace lldb_private; - -#define LLDB_OPTIONS_script -#include "CommandOptions.inc" - -Status CommandObjectScript::CommandOptions::SetOptionValue( - uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) { - Status error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'l': - language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( - option_arg, GetDefinitions()[option_idx].enum_values, - eScriptLanguageNone, error); - if (!error.Success()) - error.SetErrorStringWithFormat("unrecognized value for language '%s'", - option_arg.str().c_str()); - break; - default: - llvm_unreachable("Unimplemented option"); - } - - return error; -} - -void CommandObjectScript::CommandOptions::OptionParsingStarting( - ExecutionContext *execution_context) { - language = lldb::eScriptLanguageNone; -} - -llvm::ArrayRef<OptionDefinition> -CommandObjectScript::CommandOptions::GetDefinitions() { - return llvm::ArrayRef(g_script_options); -} - -CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter) - : CommandObjectRaw( - interpreter, "script", - "Invoke the script interpreter with provided code and display any " - "results. Start the interactive interpreter if no code is supplied.", - "script [--language <scripting-language> --] [<script-code>]") {} - -CommandObjectScript::~CommandObjectScript() = default; - -void CommandObjectScript::DoExecute(llvm::StringRef command, - CommandReturnObject &result) { - // Try parsing the language option but when the command contains a raw part - // separated by the -- delimiter. - OptionsWithRaw raw_args(command); - if (raw_args.HasArgs()) { - if (!ParseOptions(raw_args.GetArgs(), result)) - return; - command = raw_args.GetRawPart(); - } - - lldb::ScriptLanguage language = - (m_options.language == lldb::eScriptLanguageNone) - ? m_interpreter.GetDebugger().GetScriptLanguage() - : m_options.language; - - if (language == lldb::eScriptLanguageNone) { - result.AppendError( - "the script-lang setting is set to none - scripting not available"); - return; - } - - ScriptInterpreter *script_interpreter = - GetDebugger().GetScriptInterpreter(true, language); - - if (script_interpreter == nullptr) { - result.AppendError("no script interpreter"); - return; - } - - // Script might change Python code we use for formatting. Make sure we keep - // up to date with it. - DataVisualization::ForceUpdate(); - - if (command.empty()) { - script_interpreter->ExecuteInterpreterLoop(); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - return; - } - - // We can do better when reporting the status of one-liner script execution. - if (script_interpreter->ExecuteOneLine(command, &result)) - result.SetStatus(eReturnStatusSuccessFinishNoResult); - else - result.SetStatus(eReturnStatusFailed); -} diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h deleted file mode 100644 index 3a8c4a890404..000000000000 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectScript.h +++ /dev/null @@ -1,42 +0,0 @@ -//===-- CommandObjectScript.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_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H -#define LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H - -#include "lldb/Interpreter/CommandObject.h" - -namespace lldb_private { - -class CommandObjectScript : public CommandObjectRaw { -public: - CommandObjectScript(CommandInterpreter &interpreter); - ~CommandObjectScript() override; - Options *GetOptions() override { return &m_options; } - - class CommandOptions : public Options { - public: - CommandOptions() = default; - ~CommandOptions() override = default; - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override; - void OptionParsingStarting(ExecutionContext *execution_context) override; - llvm::ArrayRef<OptionDefinition> GetDefinitions() override; - lldb::ScriptLanguage language = lldb::eScriptLanguageNone; - }; - -protected: - void DoExecute(llvm::StringRef command, CommandReturnObject &result) override; - -private: - CommandOptions m_options; -}; - -} // namespace lldb_private - -#endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.cpp new file mode 100644 index 000000000000..fee0565a7c48 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.cpp @@ -0,0 +1,144 @@ +//===-- CommandObjectScripting.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 "CommandObjectScripting.h" +#include "lldb/Core/Debugger.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandOptionArgumentTable.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Args.h" + +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_scripting_run +#include "CommandOptions.inc" + +class CommandObjectScriptingRun : public CommandObjectRaw { +public: + CommandObjectScriptingRun(CommandInterpreter &interpreter) + : CommandObjectRaw( + interpreter, "scripting run", + "Invoke the script interpreter with provided code and display any " + "results. Start the interactive interpreter if no code is " + "supplied.", + "scripting run [--language <scripting-language> --] " + "[<script-code>]") {} + + ~CommandObjectScriptingRun() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() = default; + ~CommandOptions() override = default; + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'l': + language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + eScriptLanguageNone, error); + if (!error.Success()) + error.SetErrorStringWithFormat("unrecognized value for language '%s'", + option_arg.str().c_str()); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + language = lldb::eScriptLanguageNone; + } + + llvm::ArrayRef<OptionDefinition> GetDefinitions() override { + return llvm::ArrayRef(g_scripting_run_options); + } + + lldb::ScriptLanguage language = lldb::eScriptLanguageNone; + }; + +protected: + void DoExecute(llvm::StringRef command, + CommandReturnObject &result) override { + // Try parsing the language option but when the command contains a raw part + // separated by the -- delimiter. + OptionsWithRaw raw_args(command); + if (raw_args.HasArgs()) { + if (!ParseOptions(raw_args.GetArgs(), result)) + return; + command = raw_args.GetRawPart(); + } + + lldb::ScriptLanguage language = + (m_options.language == lldb::eScriptLanguageNone) + ? m_interpreter.GetDebugger().GetScriptLanguage() + : m_options.language; + + if (language == lldb::eScriptLanguageNone) { + result.AppendError( + "the script-lang setting is set to none - scripting not available"); + return; + } + + ScriptInterpreter *script_interpreter = + GetDebugger().GetScriptInterpreter(true, language); + + if (script_interpreter == nullptr) { + result.AppendError("no script interpreter"); + return; + } + + // Script might change Python code we use for formatting. Make sure we keep + // up to date with it. + DataVisualization::ForceUpdate(); + + if (command.empty()) { + script_interpreter->ExecuteInterpreterLoop(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return; + } + + // We can do better when reporting the status of one-liner script execution. + if (script_interpreter->ExecuteOneLine(command, &result)) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + } + +private: + CommandOptions m_options; +}; + +#pragma mark CommandObjectMultiwordScripting + +// CommandObjectMultiwordScripting + +CommandObjectMultiwordScripting::CommandObjectMultiwordScripting( + CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "scripting", + "Commands for operating on the scripting functionnalities.", + "scripting <subcommand> [<subcommand-options>]") { + LoadSubCommand("run", + CommandObjectSP(new CommandObjectScriptingRun(interpreter))); +} + +CommandObjectMultiwordScripting::~CommandObjectMultiwordScripting() = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.h new file mode 100644 index 000000000000..0ccd579deec0 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectScripting.h @@ -0,0 +1,25 @@ +//===-- CommandObjectScripting.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_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPTING_H +#define LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPTING_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectMultiwordScripting : public CommandObjectMultiword { +public: + CommandObjectMultiwordScripting(CommandInterpreter &interpreter); + + ~CommandObjectMultiwordScripting() override; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPTING_H diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp index d140bdfdba57..c381ba4f74f1 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSession.cpp @@ -21,20 +21,11 @@ public: "If no file if specified, transcripts will be " "saved to a temporary file.", "session save [file]") { - CommandArgumentEntry arg1; - arg1.emplace_back(eArgTypePath, eArgRepeatOptional); - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypePath, eArgRepeatOptional); } ~CommandObjectSessionSave() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - protected: void DoExecute(Args &args, CommandReturnObject &result) override { llvm::StringRef file_path; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSettings.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectSettings.cpp index 5fb7dcc80279..7bbb0dd567ab 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectSettings.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSettings.cpp @@ -245,31 +245,11 @@ public: "Show matching debugger settings and their current " "values. Defaults to showing all settings.", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData var_name_arg; - - // Define the first (and only) variant of this arg. - var_name_arg.arg_type = eArgTypeSettingVariableName; - var_name_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(var_name_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeSettingVariableName, eArgRepeatOptional); } ~CommandObjectSettingsShow() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eSettingsNameCompletion, request, - nullptr); - } - protected: void DoExecute(Args &args, CommandReturnObject &result) override { result.SetStatus(eReturnStatusSuccessFinishResult); @@ -305,19 +285,7 @@ public: "current values to a file that can be read in with " "\"settings read\". Defaults to writing all settings.", nullptr) { - CommandArgumentEntry arg1; - CommandArgumentData var_name_arg; - - // Define the first (and only) variant of this arg. - var_name_arg.arg_type = eArgTypeSettingVariableName; - var_name_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg1.push_back(var_name_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg1); + AddSimpleArgumentList(eArgTypeSettingVariableName, eArgRepeatOptional); } ~CommandObjectSettingsWrite() override = default; @@ -1005,19 +973,7 @@ public: interpreter, "settings clear", "Clear a debugger setting array, dictionary, or string. " "If '-a' option is specified, it clears all settings.", nullptr) { - CommandArgumentEntry arg; - CommandArgumentData var_name_arg; - - // Define the first (and only) variant of this arg. - var_name_arg.arg_type = eArgTypeSettingVariableName; - var_name_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(var_name_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeSettingVariableName); } ~CommandObjectSettingsClear() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp index fde74f02aea6..f54b712adfc4 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectSource.cpp @@ -158,7 +158,7 @@ protected: if (module_list.GetSize() && module_list.GetIndexForModule(module) == LLDB_INVALID_INDEX32) continue; - if (!FileSpec::Match(file_spec, line_entry.file)) + if (!FileSpec::Match(file_spec, line_entry.GetFile())) continue; if (start_line > 0 && line_entry.line < start_line) continue; @@ -239,7 +239,7 @@ protected: num_matches++; if (num_lines > 0 && num_matches > num_lines) break; - assert(cu_file_spec == line_entry.file); + assert(cu_file_spec == line_entry.GetFile()); if (!cu_header_printed) { if (num_matches > 0) strm << "\n\n"; @@ -747,24 +747,28 @@ protected: bool operator==(const SourceInfo &rhs) const { return function == rhs.function && - *line_entry.original_file_sp == *rhs.line_entry.original_file_sp && + line_entry.original_file_sp->Equal( + *rhs.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet) && line_entry.line == rhs.line_entry.line; } bool operator!=(const SourceInfo &rhs) const { return function != rhs.function || - *line_entry.original_file_sp != *rhs.line_entry.original_file_sp || + !line_entry.original_file_sp->Equal( + *rhs.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet) || line_entry.line != rhs.line_entry.line; } bool operator<(const SourceInfo &rhs) const { if (function.GetCString() < rhs.function.GetCString()) return true; - if (line_entry.file.GetDirectory().GetCString() < - rhs.line_entry.file.GetDirectory().GetCString()) + if (line_entry.GetFile().GetDirectory().GetCString() < + rhs.line_entry.GetFile().GetDirectory().GetCString()) return true; - if (line_entry.file.GetFilename().GetCString() < - rhs.line_entry.file.GetFilename().GetCString()) + if (line_entry.GetFile().GetFilename().GetCString() < + rhs.line_entry.GetFile().GetFilename().GetCString()) return true; if (line_entry.line < rhs.line_entry.line) return true; @@ -799,7 +803,7 @@ protected: sc.function->GetEndLineSourceInfo(end_file, end_line); } else { // We have an inlined function - start_file = source_info.line_entry.file; + start_file = source_info.line_entry.GetFile(); start_line = source_info.line_entry.line; end_line = start_line + m_options.num_lines; } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectStats.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectStats.cpp index 262de0bda144..53855e7d0316 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectStats.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectStats.cpp @@ -11,6 +11,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandOptionArgumentTable.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Target/Target.h" using namespace lldb; @@ -75,6 +76,33 @@ class CommandObjectStatsDump : public CommandObjectParsed { case 'a': m_all_targets = true; break; + case 's': + m_stats_options.SetSummaryOnly(true); + break; + case 'f': + m_stats_options.SetLoadAllDebugInfo(true); + break; + case 'r': + if (llvm::Expected<bool> bool_or_error = + OptionArgParser::ToBoolean("--targets", option_arg)) + m_stats_options.SetIncludeTargets(*bool_or_error); + else + error = bool_or_error.takeError(); + break; + case 'm': + if (llvm::Expected<bool> bool_or_error = + OptionArgParser::ToBoolean("--modules", option_arg)) + m_stats_options.SetIncludeModules(*bool_or_error); + else + error = bool_or_error.takeError(); + break; + case 't': + if (llvm::Expected<bool> bool_or_error = + OptionArgParser::ToBoolean("--transcript", option_arg)) + m_stats_options.SetIncludeTranscript(*bool_or_error); + else + error = bool_or_error.takeError(); + break; default: llvm_unreachable("Unimplemented option"); } @@ -83,13 +111,17 @@ class CommandObjectStatsDump : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_all_targets = false; + m_stats_options = StatisticsOptions(); } llvm::ArrayRef<OptionDefinition> GetDefinitions() override { return llvm::ArrayRef(g_statistics_dump_options); } + const StatisticsOptions &GetStatisticsOptions() { return m_stats_options; } + bool m_all_targets = false; + StatisticsOptions m_stats_options = StatisticsOptions(); }; public: @@ -109,7 +141,8 @@ protected: target = m_exe_ctx.GetTargetPtr(); result.AppendMessageWithFormatv( - "{0:2}", DebuggerStats::ReportStatistics(GetDebugger(), target)); + "{0:2}", DebuggerStats::ReportStatistics( + GetDebugger(), target, m_options.GetStatisticsOptions())); result.SetStatus(eReturnStatusSuccessFinishResult); } diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp index c3ecdb7700c2..d594330934ad 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectTarget.cpp @@ -229,19 +229,8 @@ public: m_remote_file( LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, "Fullpath to the file on the remote host if debugging remotely.") { - CommandArgumentEntry arg; - CommandArgumentData file_arg; - - // Define the first (and only) variant of this arg. - file_arg.arg_type = eArgTypeFilename; - file_arg.arg_repetition = eArgRepeatPlain; - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFilename); m_option_group.Append(&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1); @@ -257,13 +246,6 @@ public: Options *GetOptions() override { return &m_option_group; } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -510,8 +492,7 @@ public: : CommandObjectParsed( interpreter, "target select", "Select a target as the current target by target index.", nullptr) { - CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatPlain}; - m_arguments.push_back({target_arg}); + AddSimpleArgumentList(eArgTypeTargetID); } ~CommandObjectTargetSelect() override = default; @@ -593,8 +574,7 @@ public: m_option_group.Append(&m_all_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Finalize(); - CommandArgumentData target_arg{eArgTypeTargetID, eArgRepeatStar}; - m_arguments.push_back({target_arg}); + AddSimpleArgumentList(eArgTypeTargetID, eArgRepeatStar); } ~CommandObjectTargetDelete() override = default; @@ -736,19 +716,7 @@ public: "A basename or fullpath to a shared library to use in the search " "for global " "variables. This option can be specified multiple times.") { - CommandArgumentEntry arg; - CommandArgumentData var_name_arg; - - // Define the first (and only) variant of this arg. - var_name_arg.arg_type = eArgTypeVarName; - var_name_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(var_name_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeVarName, eArgRepeatPlus); m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -816,7 +784,8 @@ public: options.SetRootValueObjectName(root_name); - valobj_sp->Dump(s, options); + if (llvm::Error error = valobj_sp->Dump(s, options)) + s << "error: " << toString(std::move(error)); } static size_t GetVariableCallback(void *baton, const char *name, @@ -1250,19 +1219,7 @@ public: interpreter, "target modules search-paths query", "Transform a path using the first applicable image search path.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandArgumentData path_arg; - - // Define the first (and only) variant of this arg. - path_arg.arg_type = eArgTypeDirectoryName; - path_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(path_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeDirectoryName); } ~CommandObjectTargetModulesSearchPathsQuery() override = default; @@ -1888,19 +1845,7 @@ public: const char *syntax, uint32_t flags = 0) : CommandObjectParsed(interpreter, name, help, syntax, flags) { - CommandArgumentEntry arg; - CommandArgumentData file_arg; - - // Define the first (and only) variant of this arg. - file_arg.arg_type = eArgTypeFilename; - file_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFilename, eArgRepeatStar); } ~CommandObjectTargetModulesModuleAutoComplete() override = default; @@ -1925,19 +1870,7 @@ public: CommandInterpreter &interpreter, const char *name, const char *help, const char *syntax, uint32_t flags) : CommandObjectParsed(interpreter, name, help, syntax, flags) { - CommandArgumentEntry arg; - CommandArgumentData source_file_arg; - - // Define the first (and only) variant of this arg. - source_file_arg.arg_type = eArgTypeSourceFile; - source_file_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(source_file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeSourceFile, eArgRepeatPlus); } ~CommandObjectTargetModulesSourceFileAutoComplete() override = default; @@ -2241,8 +2174,7 @@ public: interpreter, "target modules dump pcm-info", "Dump information about the given clang module (pcm).") { // Take a single file argument. - CommandArgumentData arg{eArgTypeFilename, eArgRepeatPlain}; - m_arguments.push_back({arg}); + AddSimpleArgumentList(eArgTypeFilename); } ~CommandObjectTargetModulesDumpClangPCMInfo() override = default; @@ -2781,21 +2713,13 @@ public: LLDB_OPT_SET_1); m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Finalize(); - CommandArgumentData module_arg{eArgTypePath, eArgRepeatStar}; - m_arguments.push_back({module_arg}); + AddSimpleArgumentList(eArgTypePath, eArgRepeatStar); } ~CommandObjectTargetModulesAdd() override = default; Options *GetOptions() override { return &m_option_group; } - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - protected: OptionGroupOptions m_option_group; OptionGroupUUID m_uuid_option_group; @@ -3233,8 +3157,7 @@ public: : CommandObjectParsed( interpreter, "target modules list", "List current executable and dependent shared library images.") { - CommandArgumentData module_arg{eArgTypeShlibName, eArgRepeatStar}; - m_arguments.push_back({module_arg}); + AddSimpleArgumentList(eArgTypeModule, eArgRepeatStar); } ~CommandObjectTargetModulesList() override = default; @@ -3454,15 +3377,19 @@ protected: case 'r': { size_t ref_count = 0; + char in_shared_cache = 'Y'; + ModuleSP module_sp(module->shared_from_this()); + if (!ModuleList::ModuleIsInCache(module)) + in_shared_cache = 'N'; if (module_sp) { // Take one away to make sure we don't count our local "module_sp" ref_count = module_sp.use_count() - 1; } if (width) - strm.Printf("{%*" PRIu64 "}", width, (uint64_t)ref_count); + strm.Printf("{%c %*" PRIu64 "}", in_shared_cache, width, (uint64_t)ref_count); else - strm.Printf("{%" PRIu64 "}", (uint64_t)ref_count); + strm.Printf("{%c %" PRIu64 "}", in_shared_cache, (uint64_t)ref_count); } break; case 's': @@ -4006,19 +3933,7 @@ public: "Look up information within executable and " "dependent shared library images.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandArgumentData file_arg; - - // Define the first (and only) variant of this arg. - file_arg.arg_type = eArgTypeFilename; - file_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(file_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeFilename, eArgRepeatStar); } ~CommandObjectTargetModulesLookup() override = default; @@ -4337,19 +4252,11 @@ public: m_option_group.Append(&m_current_stack_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2); m_option_group.Finalize(); - CommandArgumentData module_arg{eArgTypeShlibName, eArgRepeatPlain}; - m_arguments.push_back({module_arg}); + AddSimpleArgumentList(eArgTypeFilename); } ~CommandObjectTargetSymbolsAdd() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr); - } - Options *GetOptions() override { return &m_option_group; } protected: @@ -4602,11 +4509,8 @@ protected: ModuleSpec module_spec; module_spec.GetUUID() = frame_module_sp->GetUUID(); - - if (FileSystem::Instance().Exists(frame_module_sp->GetPlatformFileSpec())) { - module_spec.GetArchitecture() = frame_module_sp->GetArchitecture(); - module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec(); - } + module_spec.GetArchitecture() = frame_module_sp->GetArchitecture(); + module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec(); if (!DownloadObjectAndSymbolFile(module_spec, result, flush)) { result.AppendError("unable to find debug symbols for the current frame"); @@ -4651,12 +4555,8 @@ protected: ModuleSpec module_spec; module_spec.GetUUID() = frame_module_sp->GetUUID(); - - if (FileSystem::Instance().Exists( - frame_module_sp->GetPlatformFileSpec())) { - module_spec.GetArchitecture() = frame_module_sp->GetArchitecture(); - module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec(); - } + module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec(); + module_spec.GetArchitecture() = frame_module_sp->GetArchitecture(); bool current_frame_flush = false; if (DownloadObjectAndSymbolFile(module_spec, result, current_frame_flush)) @@ -5184,8 +5084,7 @@ public: : CommandObjectParsed(interpreter, "target stop-hook delete", "Delete a stop-hook.", "target stop-hook delete [<idx>]") { - CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar}; - m_arguments.push_back({hook_arg}); + AddSimpleArgumentList(eArgTypeStopHookID, eArgRepeatStar); } ~CommandObjectTargetStopHookDelete() override = default; @@ -5195,8 +5094,7 @@ public: OptionElementVector &opt_element_vector) override { if (request.GetCursorIndex()) return; - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eStopHookIDCompletion, request, nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } protected: @@ -5240,8 +5138,7 @@ public: bool enable, const char *name, const char *help, const char *syntax) : CommandObjectParsed(interpreter, name, help, syntax), m_enable(enable) { - CommandArgumentData hook_arg{eArgTypeStopHookID, eArgRepeatStar}; - m_arguments.push_back({hook_arg}); + AddSimpleArgumentList(eArgTypeStopHookID, eArgRepeatStar); } ~CommandObjectTargetStopHookEnableDisable() override = default; @@ -5251,8 +5148,7 @@ public: OptionElementVector &opt_element_vector) override { if (request.GetCursorIndex()) return; - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eStopHookIDCompletion, request, nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } protected: diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp index a1e7e3f11361..4398cf3c3b89 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThread.cpp @@ -67,13 +67,18 @@ public: if (option_arg.getAsInteger(0, m_count)) { m_count = UINT32_MAX; error.SetErrorStringWithFormat( - "invalid integer value for option '%c'", short_option); + "invalid integer value for option '%c': %s", short_option, + option_arg.data()); } + // A count of 0 means all frames. + if (m_count == 0) + m_count = UINT32_MAX; break; case 's': if (option_arg.getAsInteger(0, m_start)) error.SetErrorStringWithFormat( - "invalid integer value for option '%c'", short_option); + "invalid integer value for option '%c': %s", short_option, + option_arg.data()); break; case 'e': { bool success; @@ -81,7 +86,8 @@ public: OptionArgParser::ToBoolean(option_arg, false, &success); if (!success) error.SetErrorStringWithFormat( - "invalid boolean value for option '%c'", short_option); + "invalid boolean value for option '%c': %s", short_option, + option_arg.data()); } break; default: llvm_unreachable("Unimplemented option"); @@ -108,8 +114,8 @@ public: CommandObjectThreadBacktrace(CommandInterpreter &interpreter) : CommandObjectIterateOverThreads( interpreter, "thread backtrace", - "Show thread call stacks. Defaults to the current thread, thread " - "indexes can be specified as arguments.\n" + "Show backtraces of thread call stacks. Defaults to the current " + "thread, thread indexes can be specified as arguments.\n" "Use the thread-index \"all\" to see all threads.\n" "Use the thread-index \"unique\" to see threads grouped by unique " "call stacks.\n" @@ -126,7 +132,7 @@ public: Options *GetOptions() override { return &m_options; } std::optional<std::string> GetRepeatCommand(Args ¤t_args, - uint32_t idx) override { + uint32_t index) override { llvm::StringRef count_opt("--count"); llvm::StringRef start_opt("--start"); @@ -145,14 +151,14 @@ public: for (size_t idx = 0; idx < num_entries; idx++) { llvm::StringRef arg_string = copy_args[idx].ref(); - if (arg_string.equals("-c") || count_opt.starts_with(arg_string)) { + if (arg_string == "-c" || count_opt.starts_with(arg_string)) { idx++; if (idx == num_entries) return std::nullopt; count_idx = idx; if (copy_args[idx].ref().getAsInteger(0, count_val)) return std::nullopt; - } else if (arg_string.equals("-s") || start_opt.starts_with(arg_string)) { + } else if (arg_string == "-s" || start_opt.starts_with(arg_string)) { idx++; if (idx == num_entries) return std::nullopt; @@ -228,9 +234,9 @@ protected: thread->GetIndexID()); return false; } - if (m_options.m_extended_backtrace) { - if (!INTERRUPT_REQUESTED(GetDebugger(), - "Interrupt skipped extended backtrace")) { + if (m_options.m_extended_backtrace) { + if (!INTERRUPT_REQUESTED(GetDebugger(), + "Interrupt skipped extended backtrace")) { DoExtendedBacktrace(thread, result); } } @@ -272,8 +278,9 @@ public: bool avoid_no_debug = OptionArgParser::ToBoolean(option_arg, true, &success); if (!success) - error.SetErrorStringWithFormat("invalid boolean value for option '%c'", - short_option); + error.SetErrorStringWithFormat( + "invalid boolean value for option '%c': %s", short_option, + option_arg.data()); else { m_step_in_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; } @@ -284,8 +291,9 @@ public: bool avoid_no_debug = OptionArgParser::ToBoolean(option_arg, true, &success); if (!success) - error.SetErrorStringWithFormat("invalid boolean value for option '%c'", - short_option); + error.SetErrorStringWithFormat( + "invalid boolean value for option '%c': %s", short_option, + option_arg.data()); else { m_step_out_avoid_no_debug = avoid_no_debug ? eLazyBoolYes : eLazyBoolNo; } @@ -293,8 +301,9 @@ public: case 'c': if (option_arg.getAsInteger(0, m_step_count)) - error.SetErrorStringWithFormat("invalid step count '%s'", - option_arg.str().c_str()); + error.SetErrorStringWithFormat( + "invalid integer value for option '%c': %s", short_option, + option_arg.data()); break; case 'm': { @@ -374,19 +383,7 @@ public: eCommandProcessMustBePaused), m_step_type(step_type), m_step_scope(step_scope), m_class_options("scripted step") { - CommandArgumentEntry arg; - CommandArgumentData thread_id_arg; - - // Define the first (and only) variant of this arg. - thread_id_arg.arg_type = eArgTypeThreadID; - thread_id_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(thread_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional); if (step_type == eStepTypeScripted) { m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, @@ -403,10 +400,7 @@ public: OptionElementVector &opt_element_vector) override { if (request.GetCursorIndex()) return; - - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, - nullptr); + CommandObject::HandleArgumentCompletion(request, opt_element_vector); } Options *GetOptions() override { return &m_all_options; } @@ -646,31 +640,11 @@ public: nullptr, eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - // Define the first (and only) variant of this arg. - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatPlus); } ~CommandObjectThreadContinue() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eThreadIndexCompletion, request, - nullptr); - } - void DoExecute(Args &command, CommandReturnObject &result) override { bool synchronous_execution = m_interpreter.GetSynchronous(); @@ -897,19 +871,7 @@ public: nullptr, eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData line_num_arg; - - // Define the first (and only) variant of this arg. - line_num_arg.arg_type = eArgTypeLineNum; - line_num_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(line_num_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeLineNum); } ~CommandObjectThreadUntil() override = default; @@ -1424,7 +1386,10 @@ public: Stream &strm = result.GetOutputStream(); ValueObjectSP exception_object_sp = thread_sp->GetCurrentException(); if (exception_object_sp) { - exception_object_sp->Dump(strm); + if (llvm::Error error = exception_object_sp->Dump(strm)) { + result.AppendError(toString(std::move(error))); + return false; + } } ThreadSP exception_thread_sp = thread_sp->GetCurrentExceptionBacktrace(); @@ -1476,9 +1441,12 @@ public: return false; } ValueObjectSP exception_object_sp = thread_sp->GetSiginfoValue(); - if (exception_object_sp) - exception_object_sp->Dump(strm); - else + if (exception_object_sp) { + if (llvm::Error error = exception_object_sp->Dump(strm)) { + result.AppendError(toString(std::move(error))); + return false; + } + } else strm.Printf("(no siginfo)\n"); strm.PutChar('\n'); @@ -1550,19 +1518,7 @@ public: eCommandRequiresFrame | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData expression_arg; - - // Define the first (and only) variant of this arg. - expression_arg.arg_type = eArgTypeExpression; - expression_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(expression_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeExpression, eArgRepeatOptional); } ~CommandObjectThreadReturn() override = default; @@ -1755,7 +1711,7 @@ protected: line = sym_ctx.line_entry.line + m_options.m_line_offset; // Try the current file, but override if asked. - FileSpec file = sym_ctx.line_entry.file; + FileSpec file = sym_ctx.line_entry.GetFile(); if (m_options.m_filenames.GetSize() == 1) file = m_options.m_filenames.GetFileSpecAtIndex(0); @@ -1930,19 +1886,7 @@ public: eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData plan_index_arg; - - // Define the first (and only) variant of this arg. - plan_index_arg.arg_type = eArgTypeUnsignedInteger; - plan_index_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(plan_index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectThreadPlanDiscard() override = default; @@ -2003,19 +1947,7 @@ public: eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData tid_arg; - - // Define the first (and only) variant of this arg. - tid_arg.arg_type = eArgTypeThreadID; - tid_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(tid_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeThreadID, eArgRepeatStar); } ~CommandObjectThreadPlanPrune() override = default; @@ -2232,8 +2164,7 @@ public: eCommandRequiresProcess | eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | eCommandProcessMustBeTraced) { - CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional); } ~CommandObjectTraceDumpFunctionCalls() override = default; @@ -2406,8 +2337,7 @@ public: eCommandRequiresProcess | eCommandRequiresThread | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | eCommandProcessMustBeTraced) { - CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatOptional}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatOptional); } ~CommandObjectTraceDumpInstructions() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp index d7fa4190a245..cdc5946547f4 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.cpp @@ -21,8 +21,7 @@ CommandObjectIterateOverThreads::CommandObjectIterateOverThreads( const char *syntax, uint32_t flags) : CommandObjectParsed(interpreter, name, help, syntax, flags) { // These commands all take thread ID's as arguments. - CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatStar}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatStar); } CommandObjectMultipleThreads::CommandObjectMultipleThreads( @@ -30,8 +29,7 @@ CommandObjectMultipleThreads::CommandObjectMultipleThreads( const char *syntax, uint32_t flags) : CommandObjectParsed(interpreter, name, help, syntax, flags) { // These commands all take thread ID's as arguments. - CommandArgumentData thread_arg{eArgTypeThreadIndex, eArgRepeatStar}; - m_arguments.push_back({thread_arg}); + AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatStar); } void CommandObjectIterateOverThreads::DoExecute(Args &command, diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h index 74d1136bab7f..3fc28efe8cf7 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectThreadUtil.h @@ -10,6 +10,7 @@ #define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H #include "lldb/Interpreter/CommandObjectMultiword.h" +#include <stack> namespace lldb_private { diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp index e0c74e29aaa6..5bcbc236301c 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectTrace.cpp @@ -89,8 +89,7 @@ public: eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | eCommandProcessMustBeTraced) { - CommandArgumentData bundle_dir{eArgTypeDirectoryName, eArgRepeatPlain}; - m_arguments.push_back({bundle_dir}); + AddSimpleArgumentList(eArgTypeDirectoryName); } void @@ -176,8 +175,7 @@ public: interpreter, "trace load", "Load a post-mortem processor trace session from a trace bundle.", "trace load <trace_description_file>") { - CommandArgumentData session_file_arg{eArgTypeFilename, eArgRepeatPlain}; - m_arguments.push_back({session_file_arg}); + AddSimpleArgumentList(eArgTypeFilename); } void @@ -332,8 +330,7 @@ public: "Show the schema of the given trace plugin.", "trace schema <plug-in>. Use the plug-in name " "\"all\" to see all schemas.\n") { - CommandArgumentData plugin_arg{eArgTypeNone, eArgRepeatPlain}; - m_arguments.push_back({plugin_arg}); + AddSimpleArgumentList(eArgTypeNone); } ~CommandObjectTraceSchema() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp index f76420f3cc68..46537dd1b98a 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectType.cpp @@ -589,15 +589,7 @@ public: : CommandObjectParsed(interpreter, "type format add", "Add a new formatting style for a type.", nullptr), m_format_options(eFormatInvalid) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); SetHelpLong( R"( @@ -784,15 +776,7 @@ public: : CommandObjectParsed(interpreter, FormatCategoryToString(formatter_kind, false)), m_formatter_kind(formatter_kind) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlain; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName); const char *kind = FormatCategoryToString(formatter_kind, true); const char *short_kind = FormatCategoryToString(formatter_kind, false); @@ -929,8 +913,7 @@ public: const char *name, const char *help) : CommandObjectParsed(interpreter, name, help, nullptr), m_formatter_kind(formatter_kind) { - CommandArgumentData category_arg{eArgTypeName, eArgRepeatOptional}; - m_arguments.push_back({category_arg}); + AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional); } ~CommandObjectTypeFormatterClear() override = default; @@ -1045,15 +1028,7 @@ public: CommandObjectTypeFormatterList(CommandInterpreter &interpreter, const char *name, const char *help) : CommandObjectParsed(interpreter, name, help, nullptr), m_options() { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatOptional; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional); } ~CommandObjectTypeFormatterList() override = default; @@ -1445,15 +1420,7 @@ CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd( : CommandObjectParsed(interpreter, "type summary add", "Add a new summary style for a type.", nullptr), IOHandlerDelegateMultiline("DONE"), m_options(interpreter) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); SetHelpLong( R"( @@ -1745,27 +1712,11 @@ public: : CommandObjectParsed(interpreter, "type category define", "Define a new category as a source of formatters.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); } ~CommandObjectTypeCategoryDefine() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request, - nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1846,27 +1797,11 @@ public: : CommandObjectParsed(interpreter, "type category enable", "Enable a category as a source of formatters.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); } ~CommandObjectTypeCategoryEnable() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request, - nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1913,27 +1848,11 @@ public: : CommandObjectParsed(interpreter, "type category delete", "Delete a category and all associated formatters.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); } ~CommandObjectTypeCategoryDelete() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request, - nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2020,27 +1939,11 @@ public: : CommandObjectParsed(interpreter, "type category disable", "Disable a category as a source of formatters.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); } ~CommandObjectTypeCategoryDisable() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eTypeCategoryNameCompletion, request, - nullptr); - } - protected: void DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2082,15 +1985,7 @@ public: : CommandObjectParsed(interpreter, "type category list", "Provide a list of all existing categories.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatOptional; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatOptional); } ~CommandObjectTypeCategoryList() override = default; @@ -2303,15 +2198,7 @@ CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd( : CommandObjectParsed(interpreter, "type synthetic add", "Add a new synthetic provider for a type.", nullptr), IOHandlerDelegateMultiline("DONE"), m_options() { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); } bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name, @@ -2508,15 +2395,7 @@ public: CommandObjectTypeFilterAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "type filter add", "Add a new filter for a type.", nullptr) { - CommandArgumentEntry type_arg; - CommandArgumentData type_style_arg; - - type_style_arg.arg_type = eArgTypeName; - type_style_arg.arg_repetition = eArgRepeatPlus; - - type_arg.push_back(type_style_arg); - - m_arguments.push_back(type_arg); + AddSimpleArgumentList(eArgTypeName, eArgRepeatPlus); SetHelpLong( R"( @@ -2630,7 +2509,7 @@ protected: if (!frame) return lang_type; - lang_type = frame->GuessLanguage(); + lang_type = frame->GuessLanguage().AsLanguageType(); if (lang_type != lldb::eLanguageTypeUnknown) return lang_type; diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp index c80868d33905..f123211e7237 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -153,12 +153,7 @@ public: interpreter, "watchpoint list", "List all watchpoints at configurable levels of detail.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointList() override = default; @@ -276,12 +271,7 @@ public: "Enable the specified disabled watchpoint(s). If " "no watchpoints are specified, enable all of them.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointEnable() override = default; @@ -350,12 +340,7 @@ public: "removing it/them. If no watchpoints are " "specified, disable them all.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointDisable() override = default; @@ -429,12 +414,7 @@ public: "Delete the specified watchpoint(s). If no " "watchpoints are specified, delete them all.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointDelete() override = default; @@ -550,12 +530,7 @@ public: "Set ignore count on the specified watchpoint(s). " "If no watchpoints are specified, set them all.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointIgnore() override = default; @@ -673,12 +648,7 @@ public: "watchpoint. " "Passing an empty argument clears the modification.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, - eArgTypeWatchpointIDRange); - // Add the entry for the first argument for this command to the object's - // arguments vector. - m_arguments.push_back(arg); + CommandObject::AddIDsArgumentData(eWatchpointArgs); } ~CommandObjectWatchpointModify() override = default; @@ -811,18 +781,7 @@ Examples: " Watches my_global_var for read/write access, with the region to watch \ corresponding to the byte size of the data type."); - CommandArgumentEntry arg; - CommandArgumentData var_name_arg; - - // Define the only variant of this arg. - var_name_arg.arg_type = eArgTypeVarName; - var_name_arg.arg_repetition = eArgRepeatPlain; - - // Push the variant into the argument entry. - arg.push_back(var_name_arg); - - // Push the data for the only argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeVarName); // Absorb the '-w' and '-s' options into our option group. m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_1, LLDB_OPT_SET_1); @@ -831,16 +790,6 @@ corresponding to the byte size of the data type."); ~CommandObjectWatchpointSetVariable() override = default; - void - HandleArgumentCompletion(CompletionRequest &request, - OptionElementVector &opt_element_vector) override { - if (request.GetCursorIndex() != 0) - return; - lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( - GetCommandInterpreter(), lldb::eVariablePathCompletion, request, - nullptr); - } - Options *GetOptions() override { return &m_option_group; } protected: @@ -1019,18 +968,7 @@ Examples: Watches write access for the 1-byte region pointed to by the address 'foo + 32')"); - CommandArgumentEntry arg; - CommandArgumentData expression_arg; - - // Define the only variant of this arg. - expression_arg.arg_type = eArgTypeExpression; - expression_arg.arg_repetition = eArgRepeatPlain; - - // Push the only variant into the argument entry. - arg.push_back(expression_arg); - - // Push the data for the only argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeExpression); // Absorb the '-w' and '-s' options into our option group. m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL, @@ -1139,9 +1077,22 @@ protected: // Fetch the type from the value object, the type of the watched object is // the pointee type - /// of the expression, so convert to that if we found a valid type. + /// of the expression, so convert to that if we found a valid type. CompilerType compiler_type(valobj_sp->GetCompilerType()); + std::optional<uint64_t> valobj_size = valobj_sp->GetByteSize(); + // Set the type as a uint8_t array if the size being watched is + // larger than the ValueObject's size (which is probably the size + // of a pointer). + if (valobj_size && size > *valobj_size) { + auto type_system = compiler_type.GetTypeSystem(); + if (type_system) { + CompilerType clang_uint8_type = + type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8); + compiler_type = clang_uint8_type.GetArrayType(size); + } + } + Status error; WatchpointSP watch_sp = target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error); diff --git a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpointCommand.cpp index b1629ceab270..aaf14540cb28 100644 --- a/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/contrib/llvm-project/lldb/source/Commands/CommandObjectWatchpointCommand.cpp @@ -162,19 +162,7 @@ initialized:" "Final Note: A warning that no watchpoint command was generated when there \ are no syntax errors may indicate that a function was declared but never called."); - CommandArgumentEntry arg; - CommandArgumentData wp_id_arg; - - // Define the first (and only) variant of this arg. - wp_id_arg.arg_type = eArgTypeWatchpointID; - wp_id_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(wp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeWatchpointID); } ~CommandObjectWatchpointCommandAdd() override = default; @@ -455,19 +443,7 @@ public: : CommandObjectParsed(interpreter, "delete", "Delete the set of commands from a watchpoint.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandArgumentData wp_id_arg; - - // Define the first (and only) variant of this arg. - wp_id_arg.arg_type = eArgTypeWatchpointID; - wp_id_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(wp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeWatchpointID); } ~CommandObjectWatchpointCommandDelete() override = default; @@ -522,19 +498,7 @@ public: "List the script or set of commands to be executed " "when the watchpoint is hit.", nullptr, eCommandRequiresTarget) { - CommandArgumentEntry arg; - CommandArgumentData wp_id_arg; - - // Define the first (and only) variant of this arg. - wp_id_arg.arg_type = eArgTypeWatchpointID; - wp_id_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(wp_id_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeWatchpointID); } ~CommandObjectWatchpointCommandList() override = default; diff --git a/contrib/llvm-project/lldb/source/Commands/Options.td b/contrib/llvm-project/lldb/source/Commands/Options.td index ed3167727bcd..24e97f3bb97d 100644 --- a/contrib/llvm-project/lldb/source/Commands/Options.td +++ b/contrib/llvm-project/lldb/source/Commands/Options.td @@ -784,7 +784,7 @@ let Command = "process save_core" in { 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." + OptionalArg<"Plugin">, Desc<"Specify a plugin name to create the core file. " "This allows core files to be saved in different formats.">; } @@ -805,19 +805,25 @@ 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">, Group<2>, Arg<"PythonClass">, - Desc<"Name of the Python class 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">, Groups<[1,2]>, - Desc<"Overwrite an existing command at this node.">; + 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 completion_type : Option<"completion-type", "C">, - 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_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 { @@ -829,7 +835,7 @@ let Command = "container add" in { Desc<"Overwrite an existing command at this node.">; } -let Command = "script" in { +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.">; @@ -930,8 +936,8 @@ let Command = "target modules list" in { 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 the reference count if the module is " - "still in the shared module cache.">; + 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>, @@ -1031,7 +1037,7 @@ let Command = "target stop hook add" in { let Command = "thread backtrace" in { def thread_backtrace_count : Option<"count", "c">, Group<1>, Arg<"Count">, - Desc<"How many frames to display (-1 for all)">; + 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>, @@ -1412,4 +1418,34 @@ let Command = "trace schema" 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_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 true, unless the '--summary' mode is enabled, in which case " + "this is turned off unless specified.">; + } diff --git a/contrib/llvm-project/lldb/source/Core/Address.cpp b/contrib/llvm-project/lldb/source/Core/Address.cpp index 6f5c366ab38a..5a4751bd5256 100644 --- a/contrib/llvm-project/lldb/source/Core/Address.cpp +++ b/contrib/llvm-project/lldb/source/Core/Address.cpp @@ -398,7 +398,7 @@ bool Address::GetDescription(Stream &s, Target &target, "Non-brief descriptions not implemented"); LineEntry line_entry; if (CalculateSymbolContextLineEntry(line_entry)) { - s.Printf(" (%s:%u:%u)", line_entry.file.GetFilename().GetCString(), + s.Printf(" (%s:%u:%u)", line_entry.GetFile().GetFilename().GetCString(), line_entry.line, line_entry.column); return true; } @@ -645,7 +645,8 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, pointer_sc.symbol != nullptr) { s->PutCString(": "); pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, - false, true, true, settings); + false, true, true, false, + settings); } } } @@ -685,7 +686,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, sc.DumpStopContext(s, exe_scope, *this, show_fullpaths, show_module, show_inlined_frames, show_function_arguments, show_function_name, - settings); + false, settings); } else { // We found a symbol but it was in a different section so it // isn't the symbol we should be showing, just show the section diff --git a/contrib/llvm-project/lldb/source/Core/AddressRange.cpp b/contrib/llvm-project/lldb/source/Core/AddressRange.cpp index 1830f2ccd47f..6cef7e149cd2 100644 --- a/contrib/llvm-project/lldb/source/Core/AddressRange.cpp +++ b/contrib/llvm-project/lldb/source/Core/AddressRange.cpp @@ -14,6 +14,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Stream.h" #include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Compiler.h" @@ -145,6 +146,10 @@ void AddressRange::Clear() { m_byte_size = 0; } +bool AddressRange::IsValid() const { + return m_base_addr.IsValid() && (m_byte_size > 0); +} + bool AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style) const { addr_t vmaddr = LLDB_INVALID_ADDRESS; @@ -203,3 +208,41 @@ void AddressRange::DumpDebug(Stream *s) const { static_cast<void *>(m_base_addr.GetSection().get()), m_base_addr.GetOffset(), GetByteSize()); } + +bool AddressRange::GetDescription(Stream *s, Target *target) const { + addr_t start_addr = m_base_addr.GetLoadAddress(target); + if (start_addr != LLDB_INVALID_ADDRESS) { + // We have a valid target and the address was resolved, or we have a base + // address with no section. Just print out a raw address range: [<addr>, + // <addr>) + s->Printf("[0x%" PRIx64 "-0x%" PRIx64 ")", start_addr, + start_addr + GetByteSize()); + return true; + } + + // Either no target or the address wasn't resolved, print as + // <module>[<file-addr>-<file-addr>) + const char *file_name = ""; + const auto section_sp = m_base_addr.GetSection(); + if (section_sp) { + if (const auto object_file = section_sp->GetObjectFile()) + file_name = object_file->GetFileSpec().GetFilename().AsCString(); + } + start_addr = m_base_addr.GetFileAddress(); + const addr_t end_addr = (start_addr == LLDB_INVALID_ADDRESS) + ? LLDB_INVALID_ADDRESS + : start_addr + GetByteSize(); + s->Printf("%s[0x%" PRIx64 "-0x%" PRIx64 ")", file_name, start_addr, end_addr); + return true; +} + +bool AddressRange::operator==(const AddressRange &rhs) { + if (!IsValid() || !rhs.IsValid()) + return false; + return m_base_addr == rhs.GetBaseAddress() && + m_byte_size == rhs.GetByteSize(); +} + +bool AddressRange::operator!=(const AddressRange &rhs) { + return !(*this == rhs); +} diff --git a/contrib/llvm-project/lldb/source/Core/AddressRangeListImpl.cpp b/contrib/llvm-project/lldb/source/Core/AddressRangeListImpl.cpp new file mode 100644 index 000000000000..d405cf0fa3ec --- /dev/null +++ b/contrib/llvm-project/lldb/source/Core/AddressRangeListImpl.cpp @@ -0,0 +1,50 @@ +//===-- AddressRangeListImpl.cpp ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/AddressRangeListImpl.h" + +using namespace lldb; +using namespace lldb_private; + +AddressRangeListImpl::AddressRangeListImpl() : m_ranges() {} + +AddressRangeListImpl & +AddressRangeListImpl::operator=(const AddressRangeListImpl &rhs) { + if (this == &rhs) + return *this; + m_ranges = rhs.m_ranges; + return *this; +} + +size_t AddressRangeListImpl::GetSize() const { return m_ranges.size(); } + +void AddressRangeListImpl::Reserve(size_t capacity) { + m_ranges.reserve(capacity); +} + +void AddressRangeListImpl::Append(const AddressRange &sb_region) { + m_ranges.emplace_back(sb_region); +} + +void AddressRangeListImpl::Append(const AddressRangeListImpl &list) { + Reserve(GetSize() + list.GetSize()); + + for (const auto &range : list.m_ranges) + Append(range); +} + +void AddressRangeListImpl::Clear() { m_ranges.clear(); } + +lldb_private::AddressRange +AddressRangeListImpl::GetAddressRangeAtIndex(size_t index) { + if (index >= GetSize()) + return AddressRange(); + return m_ranges[index]; +} + +AddressRanges &AddressRangeListImpl::ref() { return m_ranges; } diff --git a/contrib/llvm-project/lldb/source/Core/CoreProperties.td b/contrib/llvm-project/lldb/source/Core/CoreProperties.td index d89afc239276..30f715364a41 100644 --- a/contrib/llvm-project/lldb/source/Core/CoreProperties.td +++ b/contrib/llvm-project/lldb/source/Core/CoreProperties.td @@ -8,7 +8,12 @@ let Definition = "modulelist" in { def EnableBackgroundLookup: Property<"enable-background-lookup", "Boolean">, Global, DefaultFalse, - Desc<"On macOS, enable calling dsymForUUID (or an equivalent script/binary) in the background to locate symbol files that weren't found.">; + Desc<"Alias for backward compatibility: when enabled this is the equivalent to 'symbols.auto-download background'.">; + def AutoDownload: Property<"auto-download", "Enum">, + Global, + DefaultEnumValue<"eSymbolDownloadOff">, + EnumValues<"OptionEnumValues(g_auto_download_enum_values)">, + Desc<"On macOS, automatically download symbols with dsymForUUID (or an equivalent script/binary) for relevant images in the debug session.">; def ClangModulesCachePath: Property<"clang-modules-cache-path", "FileSpec">, Global, DefaultStringValue<"">, @@ -127,7 +132,7 @@ let Definition = "debugger" in { Global, DefaultStringValue<"${ansi.normal}">, Desc<"When displaying the line marker in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the line to be marked.">; - def TerminalWidth: Property<"term-width", "SInt64">, + def TerminalWidth: Property<"term-width", "UInt64">, Global, DefaultUnsignedValue<80>, Desc<"The maximum number of columns to use for displaying text.">; diff --git a/contrib/llvm-project/lldb/source/Core/Debugger.cpp b/contrib/llvm-project/lldb/source/Core/Debugger.cpp index 97311b4716ac..309e01e45658 100644 --- a/contrib/llvm-project/lldb/source/Core/Debugger.cpp +++ b/contrib/llvm-project/lldb/source/Core/Debugger.cpp @@ -15,6 +15,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/StreamAsynchronousIO.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Expression/REPL.h" @@ -103,7 +104,7 @@ static std::recursive_mutex *g_debugger_list_mutex_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain static Debugger::DebuggerList *g_debugger_list_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain -static llvm::ThreadPool *g_thread_pool = nullptr; +static llvm::DefaultThreadPool *g_thread_pool = nullptr; static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = { { @@ -365,7 +366,7 @@ bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) { uint64_t Debugger::GetTerminalWidth() const { const uint32_t idx = ePropertyTerminalWidth; - return GetPropertyAtIndexAs<int64_t>( + return GetPropertyAtIndexAs<uint64_t>( idx, g_debugger_properties[idx].default_uint_value); } @@ -608,7 +609,7 @@ void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) { "Debugger::Initialize called more than once!"); g_debugger_list_mutex_ptr = new std::recursive_mutex(); g_debugger_list_ptr = new DebuggerList(); - g_thread_pool = new llvm::ThreadPool(llvm::optimal_concurrency()); + g_thread_pool = new llvm::DefaultThreadPool(llvm::optimal_concurrency()); g_load_plugin_callback = load_plugin_callback; } @@ -742,9 +743,22 @@ DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, } void Debugger::HandleDestroyCallback() { - if (m_destroy_callback) { - m_destroy_callback(GetID(), m_destroy_callback_baton); - m_destroy_callback = nullptr; + const lldb::user_id_t user_id = GetID(); + // Invoke and remove all the callbacks in an FIFO order. Callbacks which are + // added during this loop will be appended, invoked and then removed last. + // Callbacks which are removed during this loop will not be invoked. + while (true) { + DestroyCallbackInfo callback_info; + { + std::lock_guard<std::mutex> guard(m_destroy_callback_mutex); + if (m_destroy_callbacks.empty()) + break; + // Pop the first item in the list + callback_info = m_destroy_callbacks.front(); + m_destroy_callbacks.erase(m_destroy_callbacks.begin()); + } + // Call the destroy callback with user id and baton + callback_info.callback(user_id, callback_info.baton); } } @@ -822,8 +836,8 @@ TargetSP Debugger::FindTargetWithProcess(Process *process) { return target_sp; } -ConstString Debugger::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.debugger"); +llvm::StringRef Debugger::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.debugger"); return class_name; } @@ -845,7 +859,7 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) m_loaded_plugins(), m_event_handler_thread(), m_io_handler_thread(), m_sync_broadcaster(nullptr, "lldb.debugger.sync"), m_broadcaster(m_broadcaster_manager_sp, - GetStaticBroadcasterClass().AsCString()), + GetStaticBroadcasterClass().str()), m_forward_listener_sp(), m_clear_once() { // Initialize the debugger properties as early as possible as other parts of // LLDB will start querying them during construction. @@ -859,6 +873,9 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) m_collection_sp->AppendProperty( "symbols", "Symbol lookup and cache settings.", true, ModuleList::GetGlobalModuleListProperties().GetValueProperties()); + m_collection_sp->AppendProperty( + LanguageProperties::GetSettingName(), "Language settings.", true, + Language::GetGlobalLanguageProperties().GetValueProperties()); if (m_command_interpreter_up) { m_collection_sp->AppendProperty( "interpreter", @@ -886,8 +903,8 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) } assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?"); - OptionValueSInt64 *term_width = - m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64( + OptionValueUInt64 *term_width = + m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64( ePropertyTerminalWidth); term_width->SetMinimumValue(10); term_width->SetMaximumValue(1024); @@ -1111,9 +1128,6 @@ void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) { IOHandlerSP top_reader_sp = reader_sp; while (top_reader_sp) { - if (!top_reader_sp) - break; - top_reader_sp->Run(); // Don't unwind past the starting point. @@ -1426,20 +1440,43 @@ void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, void Debugger::SetDestroyCallback( lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) { - m_destroy_callback = destroy_callback; - m_destroy_callback_baton = baton; + std::lock_guard<std::mutex> guard(m_destroy_callback_mutex); + m_destroy_callbacks.clear(); + const lldb::callback_token_t token = m_destroy_callback_next_token++; + m_destroy_callbacks.emplace_back(token, destroy_callback, baton); +} + +lldb::callback_token_t Debugger::AddDestroyCallback( + lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) { + std::lock_guard<std::mutex> guard(m_destroy_callback_mutex); + const lldb::callback_token_t token = m_destroy_callback_next_token++; + m_destroy_callbacks.emplace_back(token, destroy_callback, baton); + return token; +} + +bool Debugger::RemoveDestroyCallback(lldb::callback_token_t token) { + std::lock_guard<std::mutex> guard(m_destroy_callback_mutex); + for (auto it = m_destroy_callbacks.begin(); it != m_destroy_callbacks.end(); + ++it) { + if (it->token == token) { + m_destroy_callbacks.erase(it); + return true; + } + } + return false; } static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, std::string title, std::string details, uint64_t completed, uint64_t total, - bool is_debugger_specific) { + bool is_debugger_specific, + uint32_t progress_broadcast_bit) { // Only deliver progress events if we have any progress listeners. - const uint32_t event_type = Debugger::eBroadcastBitProgress; - if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type)) + if (!debugger.GetBroadcaster().EventTypeHasListeners(progress_broadcast_bit)) return; + EventSP event_sp(new Event( - event_type, + progress_broadcast_bit, new ProgressEventData(progress_id, std::move(title), std::move(details), completed, total, is_debugger_specific))); debugger.GetBroadcaster().BroadcastEvent(event_sp); @@ -1448,7 +1485,8 @@ static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, void Debugger::ReportProgress(uint64_t progress_id, std::string title, std::string details, uint64_t completed, uint64_t total, - std::optional<lldb::user_id_t> debugger_id) { + std::optional<lldb::user_id_t> debugger_id, + uint32_t progress_category_bit) { // Check if this progress is for a specific debugger. if (debugger_id) { // It is debugger specific, grab it and deliver the event if the debugger @@ -1457,7 +1495,8 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title, if (debugger_sp) PrivateReportProgress(*debugger_sp, progress_id, std::move(title), std::move(details), completed, total, - /*is_debugger_specific*/ true); + /*is_debugger_specific*/ true, + progress_category_bit); return; } // The progress event is not debugger specific, iterate over all debuggers @@ -1467,24 +1506,24 @@ void Debugger::ReportProgress(uint64_t progress_id, std::string title, DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) PrivateReportProgress(*(*pos), progress_id, title, details, completed, - total, /*is_debugger_specific*/ false); + total, /*is_debugger_specific*/ false, + progress_category_bit); } } -static void PrivateReportDiagnostic(Debugger &debugger, - DiagnosticEventData::Type type, +static void PrivateReportDiagnostic(Debugger &debugger, Severity severity, std::string message, bool debugger_specific) { uint32_t event_type = 0; - switch (type) { - case DiagnosticEventData::Type::Info: - assert(false && "DiagnosticEventData::Type::Info should not be broadcast"); + switch (severity) { + case eSeverityInfo: + assert(false && "eSeverityInfo should not be broadcast"); return; - case DiagnosticEventData::Type::Warning: - event_type = Debugger::eBroadcastBitWarning; + case eSeverityWarning: + event_type = lldb::eBroadcastBitWarning; break; - case DiagnosticEventData::Type::Error: - event_type = Debugger::eBroadcastBitError; + case eSeverityError: + event_type = lldb::eBroadcastBitError; break; } @@ -1492,29 +1531,32 @@ static void PrivateReportDiagnostic(Debugger &debugger, if (!broadcaster.EventTypeHasListeners(event_type)) { // Diagnostics are too important to drop. If nobody is listening, print the // diagnostic directly to the debugger's error stream. - DiagnosticEventData event_data(type, std::move(message), debugger_specific); + DiagnosticEventData event_data(severity, std::move(message), + debugger_specific); StreamSP stream = debugger.GetAsyncErrorStream(); event_data.Dump(stream.get()); return; } EventSP event_sp = std::make_shared<Event>( event_type, - new DiagnosticEventData(type, std::move(message), debugger_specific)); + new DiagnosticEventData(severity, std::move(message), debugger_specific)); broadcaster.BroadcastEvent(event_sp); } -void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type, - std::string message, +void Debugger::ReportDiagnosticImpl(Severity severity, std::string message, std::optional<lldb::user_id_t> debugger_id, std::once_flag *once) { auto ReportDiagnosticLambda = [&]() { + // Always log diagnostics to the system log. + Host::SystemLog(severity, message); + // The diagnostic subsystem is optional but we still want to broadcast // events when it's disabled. if (Diagnostics::Enabled()) Diagnostics::Instance().Report(message); // We don't broadcast info events. - if (type == DiagnosticEventData::Type::Info) + if (severity == lldb::eSeverityInfo) return; // Check if this diagnostic is for a specific debugger. @@ -1523,7 +1565,8 @@ void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type, // still exists. DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id); if (debugger_sp) - PrivateReportDiagnostic(*debugger_sp, type, std::move(message), true); + PrivateReportDiagnostic(*debugger_sp, severity, std::move(message), + true); return; } // The diagnostic event is not debugger specific, iterate over all debuggers @@ -1531,7 +1574,7 @@ void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type, if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); for (const auto &debugger : *g_debugger_list_ptr) - PrivateReportDiagnostic(*debugger, type, message, false); + PrivateReportDiagnostic(*debugger, severity, message, false); } }; @@ -1544,22 +1587,19 @@ void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type, void Debugger::ReportWarning(std::string message, std::optional<lldb::user_id_t> debugger_id, std::once_flag *once) { - ReportDiagnosticImpl(DiagnosticEventData::Type::Warning, std::move(message), - debugger_id, once); + ReportDiagnosticImpl(eSeverityWarning, std::move(message), debugger_id, once); } void Debugger::ReportError(std::string message, std::optional<lldb::user_id_t> debugger_id, std::once_flag *once) { - ReportDiagnosticImpl(DiagnosticEventData::Type::Error, std::move(message), - debugger_id, once); + ReportDiagnosticImpl(eSeverityError, std::move(message), debugger_id, once); } void Debugger::ReportInfo(std::string message, std::optional<lldb::user_id_t> debugger_id, std::once_flag *once) { - ReportDiagnosticImpl(DiagnosticEventData::Type::Info, std::move(message), - debugger_id, once); + ReportDiagnosticImpl(eSeverityInfo, std::move(message), debugger_id, once); } void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) { @@ -1567,7 +1607,7 @@ void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) { std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); for (DebuggerSP debugger_sp : *g_debugger_list_ptr) { EventSP event_sp = std::make_shared<Event>( - Debugger::eBroadcastSymbolChange, + lldb::eBroadcastSymbolChange, new SymbolChangeEventData(debugger_sp, module_spec)); debugger_sp->GetBroadcaster().BroadcastEvent(event_sp); } @@ -1874,8 +1914,9 @@ lldb::thread_result_t Debugger::DefaultEventHandler() { CommandInterpreter::eBroadcastBitAsynchronousErrorData); listener_sp->StartListeningForEvents( - &m_broadcaster, eBroadcastBitProgress | eBroadcastBitWarning | - eBroadcastBitError | eBroadcastSymbolChange); + &m_broadcaster, lldb::eBroadcastBitProgress | lldb::eBroadcastBitWarning | + lldb::eBroadcastBitError | + lldb::eBroadcastSymbolChange); // Let the thread that spawned us know that we have started up and that we // are now listening to all required events so no events get missed @@ -1927,11 +1968,11 @@ lldb::thread_result_t Debugger::DefaultEventHandler() { } } } else if (broadcaster == &m_broadcaster) { - if (event_type & Debugger::eBroadcastBitProgress) + if (event_type & lldb::eBroadcastBitProgress) HandleProgressEvent(event_sp); - else if (event_type & Debugger::eBroadcastBitWarning) + else if (event_type & lldb::eBroadcastBitWarning) HandleDiagnosticEvent(event_sp); - else if (event_type & Debugger::eBroadcastBitError) + else if (event_type & lldb::eBroadcastBitError) HandleDiagnosticEvent(event_sp); } } @@ -2190,7 +2231,7 @@ Status Debugger::RunREPL(LanguageType language, const char *repl_options) { return err; } -llvm::ThreadPool &Debugger::GetThreadPool() { +llvm::ThreadPoolInterface &Debugger::GetThreadPool() { assert(g_thread_pool && "Debugger::GetThreadPool called before Debugger::Initialize"); return *g_thread_pool; diff --git a/contrib/llvm-project/lldb/source/Core/DebuggerEvents.cpp b/contrib/llvm-project/lldb/source/Core/DebuggerEvents.cpp index dd77fff349a6..2fa6efd155af 100644 --- a/contrib/llvm-project/lldb/source/Core/DebuggerEvents.cpp +++ b/contrib/llvm-project/lldb/source/Core/DebuggerEvents.cpp @@ -9,6 +9,7 @@ #include "lldb/Core/DebuggerEvents.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" +#include "lldb/Core/Progress.h" #include "llvm/Support/WithColor.h" using namespace lldb_private; @@ -41,7 +42,7 @@ void ProgressEventData::Dump(Stream *s) const { s->PutCString(", type = update"); // If m_total is UINT64_MAX, there is no progress to report, just "start" // and "end". If it isn't we will show the completed and total amounts. - if (m_total != UINT64_MAX) + if (m_total != Progress::kNonDeterministicTotal) s->Printf(", progress = %" PRIu64 " of %" PRIu64, m_completed, m_total); } @@ -72,19 +73,19 @@ ProgressEventData::GetAsStructuredData(const Event *event_ptr) { } llvm::StringRef DiagnosticEventData::GetPrefix() const { - switch (m_type) { - case Type::Info: + switch (m_severity) { + case Severity::eSeverityInfo: return "info"; - case Type::Warning: + case Severity::eSeverityWarning: return "warning"; - case Type::Error: + case Severity::eSeverityError: return "error"; } llvm_unreachable("Fully covered switch above!"); } void DiagnosticEventData::Dump(Stream *s) const { - llvm::HighlightColor color = m_type == Type::Warning + llvm::HighlightColor color = m_severity == lldb::eSeverityWarning ? llvm::HighlightColor::Warning : llvm::HighlightColor::Error; llvm::WithColor(s->AsRawOstream(), color, llvm::ColorMode::Enable) diff --git a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp index 7b07fcb26813..9286f62058bc 100644 --- a/contrib/llvm-project/lldb/source/Core/Disassembler.cpp +++ b/contrib/llvm-project/lldb/source/Core/Disassembler.cpp @@ -201,7 +201,7 @@ Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) { uint32_t func_decl_line; sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line); - if (func_decl_file != prologue_end_line.file && + if (func_decl_file != prologue_end_line.GetFile() && func_decl_file != prologue_end_line.original_file_sp->GetSpecOnly()) return {}; @@ -354,7 +354,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, } if (sc.line_entry.IsValid()) { SourceLine this_line; - this_line.file = sc.line_entry.file; + this_line.file = sc.line_entry.GetFile(); this_line.line = sc.line_entry.line; this_line.column = sc.line_entry.column; if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line)) @@ -406,7 +406,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, uint32_t func_decl_line; sc.function->GetStartLineSourceInfo(func_decl_file, func_decl_line); - if (func_decl_file == prologue_end_line.file || + if (func_decl_file == prologue_end_line.GetFile() || func_decl_file == prologue_end_line.original_file_sp->GetSpecOnly()) { // Add all the lines between the function declaration and @@ -439,7 +439,7 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, if (sc != prev_sc && sc.comp_unit && sc.line_entry.IsValid()) { SourceLine this_line; - this_line.file = sc.line_entry.file; + this_line.file = sc.line_entry.GetFile(); this_line.line = sc.line_entry.line; if (!ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, @@ -1117,8 +1117,7 @@ size_t Disassembler::ParseInstructions(Target &target, Address start, // Disassembler copy constructor Disassembler::Disassembler(const ArchSpec &arch, const char *flavor) - : m_arch(arch), m_instruction_list(), m_base_addr(LLDB_INVALID_ADDRESS), - m_flavor() { + : m_arch(arch), m_instruction_list(), m_flavor() { if (flavor == nullptr) m_flavor.assign("default"); else diff --git a/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp b/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp index 986c9a181919..826edd7bab04 100644 --- a/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp +++ b/contrib/llvm-project/lldb/source/Core/DumpDataExtractor.cpp @@ -150,8 +150,8 @@ static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s, if (bytes_consumed) { offset += bytes_consumed; const bool show_address = base_addr != LLDB_INVALID_ADDRESS; - const bool show_bytes = true; - const bool show_control_flow_kind = true; + const bool show_bytes = false; + const bool show_control_flow_kind = false; ExecutionContext exe_ctx; exe_scope->CalculateExecutionContext(exe_ctx); disassembler_sp->GetInstructionList().Dump( diff --git a/contrib/llvm-project/lldb/source/Core/DumpRegisterInfo.cpp b/contrib/llvm-project/lldb/source/Core/DumpRegisterInfo.cpp index 833479541690..eccc6784cd49 100644 --- a/contrib/llvm-project/lldb/source/Core/DumpRegisterInfo.cpp +++ b/contrib/llvm-project/lldb/source/Core/DumpRegisterInfo.cpp @@ -111,6 +111,11 @@ void lldb_private::DoDumpRegisterInfo( }; DumpList(strm, " In sets: ", in_sets, emit_set); - if (flags_type) + if (flags_type) { strm.Printf("\n\n%s", flags_type->AsTable(terminal_width).c_str()); + + std::string enumerators = flags_type->DumpEnums(terminal_width); + if (enumerators.size()) + strm << "\n\n" << enumerators; + } } diff --git a/contrib/llvm-project/lldb/source/Core/DumpRegisterValue.cpp b/contrib/llvm-project/lldb/source/Core/DumpRegisterValue.cpp index 463aa5926772..90b31fd0e865 100644 --- a/contrib/llvm-project/lldb/source/Core/DumpRegisterValue.cpp +++ b/contrib/llvm-project/lldb/source/Core/DumpRegisterValue.cpp @@ -54,7 +54,8 @@ static void dump_type_value(lldb_private::CompilerType &fields_type, T value, }; dump_options.SetChildPrintingDecider(decider).SetHideRootType(true); - vobj_sp->Dump(strm, dump_options); + if (llvm::Error error = vobj_sp->Dump(strm, dump_options)) + strm << "error: " << toString(std::move(error)); } void lldb_private::DumpRegisterValue(const RegisterValue ®_val, Stream &s, diff --git a/contrib/llvm-project/lldb/source/Core/DynamicLoader.cpp b/contrib/llvm-project/lldb/source/Core/DynamicLoader.cpp index 7871be6fc451..7758a87403b5 100644 --- a/contrib/llvm-project/lldb/source/Core/DynamicLoader.cpp +++ b/contrib/llvm-project/lldb/source/Core/DynamicLoader.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/MemoryRegionInfo.h" @@ -195,20 +196,37 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress( Target &target = process->GetTarget(); Status error; + StreamString prog_str; + if (!name.empty()) { + prog_str << name.str() << " "; + } + if (uuid.IsValid()) + prog_str << uuid.GetAsString(); + if (value_is_offset == 0 && value != LLDB_INVALID_ADDRESS) { + prog_str << "at 0x"; + prog_str.PutHex64(value); + } + if (!uuid.IsValid() && !value_is_offset) { memory_module_sp = ReadUnnamedMemoryModule(process, value, name); - if (memory_module_sp) + if (memory_module_sp) { uuid = memory_module_sp->GetUUID(); + if (uuid.IsValid()) { + prog_str << " "; + prog_str << uuid.GetAsString(); + } + } } ModuleSpec module_spec; module_spec.GetUUID() = uuid; FileSpec name_filespec(name); - if (FileSystem::Instance().Exists(name_filespec)) - module_spec.GetFileSpec() = name_filespec; if (uuid.IsValid()) { + Progress progress("Locating binary", prog_str.GetString().str()); + // Has lldb already seen a module with this UUID? + // Or have external lookup enabled in DebugSymbols on macOS. if (!module_sp) error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr, nullptr, nullptr); diff --git a/contrib/llvm-project/lldb/source/Core/FormatEntity.cpp b/contrib/llvm-project/lldb/source/Core/FormatEntity.cpp index 3c665c2eb213..4e1f37099148 100644 --- a/contrib/llvm-project/lldb/source/Core/FormatEntity.cpp +++ b/contrib/llvm-project/lldb/source/Core/FormatEntity.cpp @@ -57,6 +57,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Regex.h" #include "llvm/TargetParser/Triple.h" #include <cctype> @@ -658,6 +659,37 @@ static char ConvertValueObjectStyleToChar( return '\0'; } +/// Options supported by format_provider<T> for integral arithmetic types. +/// See table in FormatProviders.h. +static llvm::Regex LLVMFormatPattern{"x[-+]?\\d*|n|d", llvm::Regex::IgnoreCase}; + +static bool DumpValueWithLLVMFormat(Stream &s, llvm::StringRef options, + ValueObject &valobj) { + std::string formatted; + std::string llvm_format = ("{0:" + options + "}").str(); + + auto type_info = valobj.GetTypeInfo(); + if ((type_info & eTypeIsInteger) && LLVMFormatPattern.match(options)) { + if (type_info & eTypeIsSigned) { + bool success = false; + int64_t integer = valobj.GetValueAsSigned(0, &success); + if (success) + formatted = llvm::formatv(llvm_format.data(), integer); + } else { + bool success = false; + uint64_t integer = valobj.GetValueAsUnsigned(0, &success); + if (success) + formatted = llvm::formatv(llvm_format.data(), integer); + } + } + + if (formatted.empty()) + return false; + + s.Write(formatted.data(), formatted.size()); + return true; +} + static bool DumpValue(Stream &s, const SymbolContext *sc, const ExecutionContext *exe_ctx, const FormatEntity::Entry &entry, ValueObject *valobj) { @@ -728,9 +760,12 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, return RunScriptFormatKeyword(s, sc, exe_ctx, valobj, entry.string.c_str()); } - llvm::StringRef subpath(entry.string); + auto split = llvm::StringRef(entry.string).split(':'); + auto subpath = split.first; + auto llvm_format = split.second; + // simplest case ${var}, just print valobj's value - if (entry.string.empty()) { + if (subpath.empty()) { if (entry.printf_format.empty() && entry.fmt == eFormatDefault && entry.number == ValueObject::eValueObjectRepresentationStyleValue) was_plain_var = true; @@ -739,7 +774,7 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, target = valobj; } else // this is ${var.something} or multiple .something nested { - if (entry.string[0] == '[') + if (subpath[0] == '[') was_var_indexed = true; ScanBracketedRange(subpath, close_bracket_index, var_name_final_if_array_range, index_lower, @@ -747,14 +782,11 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, Status error; - const std::string &expr_path = entry.string; - - LLDB_LOGF(log, "[Debugger::FormatPrompt] symbol to expand: %s", - expr_path.c_str()); + LLDB_LOG(log, "[Debugger::FormatPrompt] symbol to expand: {0}", subpath); target = valobj - ->GetValueForExpressionPath(expr_path.c_str(), &reason_to_stop, + ->GetValueForExpressionPath(subpath, &reason_to_stop, &final_value_type, options, &what_next) .get(); @@ -883,8 +915,18 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, } if (!is_array_range) { - LLDB_LOGF(log, - "[Debugger::FormatPrompt] dumping ordinary printable output"); + if (!llvm_format.empty()) { + if (DumpValueWithLLVMFormat(s, llvm_format, *target)) { + LLDB_LOGF(log, "dumping using llvm format"); + return true; + } else { + LLDB_LOG( + log, + "empty output using llvm format '{0}' - with type info flags {1}", + entry.printf_format, target->GetTypeInfo()); + } + } + LLDB_LOGF(log, "dumping ordinary printable output"); return target->DumpPrintableRepresentation(s, val_obj_display, custom_format); } else { @@ -926,7 +968,7 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, s.PutChar('['); if (index_higher < 0) - index_higher = valobj->GetNumChildren() - 1; + index_higher = valobj->GetNumChildrenIgnoringErrors() - 1; uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); @@ -1359,7 +1401,10 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject(stop_info_sp); if (return_valobj_sp) { - return_valobj_sp->Dump(s); + if (llvm::Error error = return_valobj_sp->Dump(s)) { + s << "error: " << toString(std::move(error)); + return false; + } return true; } } @@ -1376,7 +1421,11 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, ExpressionVariableSP expression_var_sp = StopInfo::GetExpressionVariable(stop_info_sp); if (expression_var_sp && expression_var_sp->GetValueObject()) { - expression_var_sp->GetValueObject()->Dump(s); + if (llvm::Error error = + expression_var_sp->GetValueObject()->Dump(s)) { + s << "error: " << toString(std::move(error)); + return false; + } return true; } } @@ -1792,7 +1841,7 @@ bool FormatEntity::Format(const Entry &entry, Stream &s, if (sc && sc->line_entry.IsValid()) { Module *module = sc->module_sp.get(); if (module) { - if (DumpFile(s, sc->line_entry.file, (FileKind)entry.number)) + if (DumpFile(s, sc->line_entry.GetFile(), (FileKind)entry.number)) return true; } } @@ -1879,7 +1928,7 @@ static Status ParseEntry(const llvm::StringRef &format_str, const size_t n = parent->num_children; for (size_t i = 0; i < n; ++i) { const Definition *entry_def = parent->children + i; - if (key.equals(entry_def->name) || entry_def->name[0] == '*') { + if (key == entry_def->name || entry_def->name[0] == '*') { llvm::StringRef value; if (sep_char) value = @@ -1960,7 +2009,7 @@ static const Definition *FindEntry(const llvm::StringRef &format_str, const size_t n = parent->num_children; for (size_t i = 0; i < n; ++i) { const Definition *entry_def = parent->children + i; - if (p.first.equals(entry_def->name) || entry_def->name[0] == '*') { + if (p.first == entry_def->name || entry_def->name[0] == '*') { if (p.second.empty()) { if (format_str.back() == '.') remainder = format_str.drop_front(format_str.size() - 1); @@ -2121,90 +2170,81 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, } break; case '$': - if (format.size() == 1) { - // '$' at the end of a format string, just print the '$' + format = format.drop_front(); // Skip the '$' + if (format.empty() || format.front() != '{') { + // Print '$' when not followed by '{'. parent_entry.AppendText("$"); } else { - format = format.drop_front(); // Skip the '$' - - if (format[0] == '{') { - format = format.drop_front(); // Skip the '{' - - llvm::StringRef variable, variable_format; - error = FormatEntity::ExtractVariableInfo(format, variable, - variable_format); - if (error.Fail()) - return error; - bool verify_is_thread_id = false; - Entry entry; - if (!variable_format.empty()) { - entry.printf_format = variable_format.str(); - - // If the format contains a '%' we are going to assume this is a - // printf style format. So if you want to format your thread ID - // using "0x%llx" you can use: ${thread.id%0x%llx} - // - // If there is no '%' in the format, then it is assumed to be a - // LLDB format name, or one of the extended formats specified in - // the switch statement below. - - if (entry.printf_format.find('%') == std::string::npos) { - bool clear_printf = false; + format = format.drop_front(); // Skip the '{' + + llvm::StringRef variable, variable_format; + error = FormatEntity::ExtractVariableInfo(format, variable, + variable_format); + if (error.Fail()) + return error; + bool verify_is_thread_id = false; + Entry entry; + if (!variable_format.empty()) { + entry.printf_format = variable_format.str(); + + // If the format contains a '%' we are going to assume this is a + // printf style format. So if you want to format your thread ID + // using "0x%llx" you can use: ${thread.id%0x%llx} + // + // If there is no '%' in the format, then it is assumed to be a + // LLDB format name, or one of the extended formats specified in + // the switch statement below. + + if (entry.printf_format.find('%') == std::string::npos) { + bool clear_printf = false; + + if (entry.printf_format.size() == 1) { + switch (entry.printf_format[0]) { + case '@': // if this is an @ sign, print ObjC description + entry.number = ValueObject:: + eValueObjectRepresentationStyleLanguageSpecific; + clear_printf = true; + break; + case 'V': // if this is a V, print the value using the default + // format + entry.number = + ValueObject::eValueObjectRepresentationStyleValue; + clear_printf = true; + break; + case 'L': // if this is an L, print the location of the value + entry.number = + ValueObject::eValueObjectRepresentationStyleLocation; + clear_printf = true; + break; + case 'S': // if this is an S, print the summary after all + entry.number = + ValueObject::eValueObjectRepresentationStyleSummary; + clear_printf = true; + break; + case '#': // if this is a '#', print the number of children + entry.number = + ValueObject::eValueObjectRepresentationStyleChildrenCount; + clear_printf = true; + break; + case 'T': // if this is a 'T', print the type + entry.number = ValueObject::eValueObjectRepresentationStyleType; + clear_printf = true; + break; + case 'N': // if this is a 'N', print the name + entry.number = ValueObject::eValueObjectRepresentationStyleName; + clear_printf = true; + break; + case '>': // if this is a '>', print the expression path + entry.number = + ValueObject::eValueObjectRepresentationStyleExpressionPath; + clear_printf = true; + break; + } + } + if (entry.number == 0) { if (FormatManager::GetFormatFromCString( - entry.printf_format.c_str(), false, entry.fmt)) { - // We have an LLDB format, so clear the printf format - clear_printf = true; - } else if (entry.printf_format.size() == 1) { - switch (entry.printf_format[0]) { - case '@': // if this is an @ sign, print ObjC description - entry.number = ValueObject:: - eValueObjectRepresentationStyleLanguageSpecific; - clear_printf = true; - break; - case 'V': // if this is a V, print the value using the default - // format - entry.number = - ValueObject::eValueObjectRepresentationStyleValue; - clear_printf = true; - break; - case 'L': // if this is an L, print the location of the value - entry.number = - ValueObject::eValueObjectRepresentationStyleLocation; - clear_printf = true; - break; - case 'S': // if this is an S, print the summary after all - entry.number = - ValueObject::eValueObjectRepresentationStyleSummary; - clear_printf = true; - break; - case '#': // if this is a '#', print the number of children - entry.number = - ValueObject::eValueObjectRepresentationStyleChildrenCount; - clear_printf = true; - break; - case 'T': // if this is a 'T', print the type - entry.number = - ValueObject::eValueObjectRepresentationStyleType; - clear_printf = true; - break; - case 'N': // if this is a 'N', print the name - entry.number = - ValueObject::eValueObjectRepresentationStyleName; - clear_printf = true; - break; - case '>': // if this is a '>', print the expression path - entry.number = ValueObject:: - eValueObjectRepresentationStyleExpressionPath; - clear_printf = true; - break; - default: - error.SetErrorStringWithFormat("invalid format: '%s'", - entry.printf_format.c_str()); - return error; - } - } else if (FormatManager::GetFormatFromCString( - entry.printf_format.c_str(), true, entry.fmt)) { + entry.printf_format.c_str(), entry.fmt)) { clear_printf = true; } else if (entry.printf_format == "tid") { verify_is_thread_id = true; @@ -2213,56 +2253,65 @@ static Status ParseInternal(llvm::StringRef &format, Entry &parent_entry, entry.printf_format.c_str()); return error; } - - // Our format string turned out to not be a printf style format - // so lets clear the string - if (clear_printf) - entry.printf_format.clear(); } - } - // Check for dereferences - if (variable[0] == '*') { - entry.deref = true; - variable = variable.drop_front(); + // Our format string turned out to not be a printf style format + // so lets clear the string + if (clear_printf) + entry.printf_format.clear(); } + } - error = ParseEntry(variable, &g_root, entry); - if (error.Fail()) + // Check for dereferences + if (variable[0] == '*') { + entry.deref = true; + variable = variable.drop_front(); + } + + error = ParseEntry(variable, &g_root, entry); + if (error.Fail()) + return error; + + llvm::StringRef entry_string(entry.string); + if (entry_string.contains(':')) { + auto [_, llvm_format] = entry_string.split(':'); + if (!llvm_format.empty() && !LLVMFormatPattern.match(llvm_format)) { + error.SetErrorStringWithFormat("invalid llvm format: '%s'", + llvm_format.data()); return error; + } + } - if (verify_is_thread_id) { - if (entry.type != Entry::Type::ThreadID && - entry.type != Entry::Type::ThreadProtocolID) { - error.SetErrorString("the 'tid' format can only be used on " - "${thread.id} and ${thread.protocol_id}"); - } + if (verify_is_thread_id) { + if (entry.type != Entry::Type::ThreadID && + entry.type != Entry::Type::ThreadProtocolID) { + error.SetErrorString("the 'tid' format can only be used on " + "${thread.id} and ${thread.protocol_id}"); } + } - switch (entry.type) { - case Entry::Type::Variable: - case Entry::Type::VariableSynthetic: - if (entry.number == 0) { - if (entry.string.empty()) - entry.number = - ValueObject::eValueObjectRepresentationStyleValue; - else - entry.number = - ValueObject::eValueObjectRepresentationStyleSummary; - } - break; - default: - // Make sure someone didn't try to dereference anything but ${var} - // or ${svar} - if (entry.deref) { - error.SetErrorStringWithFormat( - "${%s} can't be dereferenced, only ${var} and ${svar} can.", - variable.str().c_str()); - return error; - } + switch (entry.type) { + case Entry::Type::Variable: + case Entry::Type::VariableSynthetic: + if (entry.number == 0) { + if (entry.string.empty()) + entry.number = ValueObject::eValueObjectRepresentationStyleValue; + else + entry.number = + ValueObject::eValueObjectRepresentationStyleSummary; + } + break; + default: + // Make sure someone didn't try to dereference anything but ${var} + // or ${svar} + if (entry.deref) { + error.SetErrorStringWithFormat( + "${%s} can't be dereferenced, only ${var} and ${svar} can.", + variable.str().c_str()); + return error; } - parent_entry.AppendEntry(std::move(entry)); } + parent_entry.AppendEntry(std::move(entry)); } break; } @@ -2303,13 +2352,13 @@ Status FormatEntity::ExtractVariableInfo(llvm::StringRef &format_str, bool FormatEntity::FormatFileSpec(const FileSpec &file_spec, Stream &s, llvm::StringRef variable_name, llvm::StringRef variable_format) { - if (variable_name.empty() || variable_name.equals(".fullpath")) { + if (variable_name.empty() || variable_name == ".fullpath") { file_spec.Dump(s.AsRawOstream()); return true; - } else if (variable_name.equals(".basename")) { + } else if (variable_name == ".basename") { s.PutCString(file_spec.GetFilename().GetStringRef()); return true; - } else if (variable_name.equals(".dirname")) { + } else if (variable_name == ".dirname") { s.PutCString(file_spec.GetFilename().GetStringRef()); return true; } @@ -2392,7 +2441,7 @@ void FormatEntity::AutoComplete(CompletionRequest &request) { // "${thread.id" <TAB> request.AddCompletion(MakeMatch(str, "}")); } - } else if (remainder.equals(".")) { + } else if (remainder == ".") { // "${thread." <TAB> StringList new_matches; AddMatches(entry_def, str, llvm::StringRef(), new_matches); diff --git a/contrib/llvm-project/lldb/source/Core/IOHandlerCursesGUI.cpp b/contrib/llvm-project/lldb/source/Core/IOHandlerCursesGUI.cpp index 620e68a28510..d922d32f9105 100644 --- a/contrib/llvm-project/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/contrib/llvm-project/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -4519,7 +4519,7 @@ struct Row { calculated_children = true; ValueObjectSP valobj = value.GetSP(); if (valobj) { - const size_t num_children = valobj->GetNumChildren(); + const uint32_t num_children = valobj->GetNumChildrenIgnoringErrors(); for (size_t i = 0; i < num_children; ++i) { children.push_back(Row(valobj->GetChildAtIndex(i), this)); } @@ -6894,7 +6894,8 @@ public: if (context_changed) m_selected_line = m_pc_line; - if (m_file_sp && m_file_sp->GetFileSpec() == m_sc.line_entry.file) { + if (m_file_sp && + m_file_sp->GetFileSpec() == m_sc.line_entry.GetFile()) { // Same file, nothing to do, we should either have the lines or // not (source file missing) if (m_selected_line >= static_cast<size_t>(m_first_visible_line)) { @@ -6909,8 +6910,8 @@ public: } else { // File changed, set selected line to the line with the PC m_selected_line = m_pc_line; - m_file_sp = - m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file); + m_file_sp = m_debugger.GetSourceManager().GetFile( + m_sc.line_entry.GetFile()); if (m_file_sp) { const size_t num_lines = m_file_sp->GetNumLines(); m_line_width = 1; @@ -7000,7 +7001,7 @@ public: LineEntry bp_loc_line_entry; if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry( bp_loc_line_entry)) { - if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file) { + if (m_file_sp->GetFileSpec() == bp_loc_line_entry.GetFile()) { bp_lines.insert(bp_loc_line_entry.line); } } @@ -7477,7 +7478,7 @@ public: LineEntry bp_loc_line_entry; if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry( bp_loc_line_entry)) { - if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file && + if (m_file_sp->GetFileSpec() == bp_loc_line_entry.GetFile() && m_selected_line + 1 == bp_loc_line_entry.line) { bool removed = exe_ctx.GetTargetRef().RemoveBreakpointByID(bp_sp->GetID()); diff --git a/contrib/llvm-project/lldb/source/Core/Mangled.cpp b/contrib/llvm-project/lldb/source/Core/Mangled.cpp index 23ae3913093f..387c4fac6b0f 100644 --- a/contrib/llvm-project/lldb/source/Core/Mangled.cpp +++ b/contrib/llvm-project/lldb/source/Core/Mangled.cpp @@ -19,6 +19,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/lldb-enumerations.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Demangle/Demangle.h" #include "llvm/Support/Compiler.h" @@ -48,8 +49,15 @@ Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) { if (name.starts_with("_R")) return Mangled::eManglingSchemeRustV0; - if (name.starts_with("_D")) - return Mangled::eManglingSchemeD; + if (name.starts_with("_D")) { + // A dlang mangled name begins with `_D`, followed by a numeric length. One + // known exception is the symbol `_Dmain`. + // See `SymbolName` and `LName` in + // https://dlang.org/spec/abi.html#name_mangling + llvm::StringRef buf = name.drop_front(2); + if (!buf.empty() && (llvm::isDigit(buf.front()) || name == "_Dmain")) + return Mangled::eManglingSchemeD; + } if (name.starts_with("_Z")) return Mangled::eManglingSchemeItanium; @@ -125,7 +133,7 @@ void Mangled::SetValue(ConstString name) { } // Local helpers for different demangling implementations. -static char *GetMSVCDemangledStr(std::string_view M) { +static char *GetMSVCDemangledStr(llvm::StringRef M) { char *demangled_cstr = llvm::microsoftDemangle( M, nullptr, nullptr, llvm::MSDemangleFlags( @@ -169,27 +177,29 @@ static char *GetItaniumDemangledStr(const char *M) { return demangled_cstr; } -static char *GetRustV0DemangledStr(std::string_view M) { +static char *GetRustV0DemangledStr(llvm::StringRef M) { char *demangled_cstr = llvm::rustDemangle(M); if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr && demangled_cstr[0]) LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr); else - LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle", M); + LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle", + static_cast<std::string_view>(M)); } return demangled_cstr; } -static char *GetDLangDemangledStr(std::string_view M) { +static char *GetDLangDemangledStr(llvm::StringRef M) { char *demangled_cstr = llvm::dlangDemangle(M); if (Log *log = GetLog(LLDBLog::Demangle)) { if (demangled_cstr && demangled_cstr[0]) LLDB_LOG(log, "demangled dlang: {0} -> \"{1}\"", M, demangled_cstr); else - LLDB_LOG(log, "demangled dlang: {0} -> error: failed to demangle", M); + LLDB_LOG(log, "demangled dlang: {0} -> error: failed to demangle", + static_cast<std::string_view>(M)); } return demangled_cstr; @@ -308,6 +318,8 @@ ConstString Mangled::GetDemangledName() const { } ConstString Mangled::GetDisplayDemangledName() const { + if (Language *lang = Language::FindPlugin(GuessLanguage())) + return lang->GetDisplayDemangledName(*this); return GetDemangledName(); } diff --git a/contrib/llvm-project/lldb/source/Core/Module.cpp b/contrib/llvm-project/lldb/source/Core/Module.cpp index 8ffa35518b3c..9c105b3f0e57 100644 --- a/contrib/llvm-project/lldb/source/Core/Module.cpp +++ b/contrib/llvm-project/lldb/source/Core/Module.cpp @@ -1009,6 +1009,8 @@ SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) { m_symfile_up.reset( SymbolVendor::FindPlugin(shared_from_this(), feedback_strm)); m_did_load_symfile = true; + if (m_unwind_table) + m_unwind_table->Update(); } } } @@ -1239,9 +1241,9 @@ void Module::SectionFileAddressesChanged() { UnwindTable &Module::GetUnwindTable() { if (!m_unwind_table) { - m_unwind_table.emplace(*this); if (!m_symfile_spec) SymbolLocator::DownloadSymbolFileAsync(GetUUID()); + m_unwind_table.emplace(*this); } return *m_unwind_table; } @@ -1359,15 +1361,10 @@ void Module::SetSymbolFileFileSpec(const FileSpec &file) { // one obj_file->ClearSymtab(); - // Clear the unwind table too, as that may also be affected by the - // symbol file information. - m_unwind_table.reset(); - // The symbol file might be a directory bundle ("/tmp/a.out.dSYM") // instead of a full path to the symbol file within the bundle // ("/tmp/a.out.dSYM/Contents/Resources/DWARF/a.out"). So we need to // check this - if (FileSystem::Instance().IsDirectory(file)) { std::string new_path(file.GetPath()); std::string old_path(obj_file->GetFileSpec().GetPath()); diff --git a/contrib/llvm-project/lldb/source/Core/ModuleList.cpp b/contrib/llvm-project/lldb/source/Core/ModuleList.cpp index b7f393636ba2..b03490bacf95 100644 --- a/contrib/llvm-project/lldb/source/Core/ModuleList.cpp +++ b/contrib/llvm-project/lldb/source/Core/ModuleList.cpp @@ -104,10 +104,15 @@ bool ModuleListProperties::SetEnableExternalLookup(bool new_value) { return SetPropertyAtIndex(ePropertyEnableExternalLookup, new_value); } -bool ModuleListProperties::GetEnableBackgroundLookup() const { - const uint32_t idx = ePropertyEnableBackgroundLookup; - return GetPropertyAtIndexAs<bool>( - idx, g_modulelist_properties[idx].default_uint_value != 0); +SymbolDownload ModuleListProperties::GetSymbolAutoDownload() const { + // Backward compatibility alias. + if (GetPropertyAtIndexAs<bool>(ePropertyEnableBackgroundLookup, false)) + return eSymbolDownloadBackground; + + const uint32_t idx = ePropertyAutoDownload; + return GetPropertyAtIndexAs<lldb::SymbolDownload>( + idx, static_cast<lldb::SymbolDownload>( + g_modulelist_properties[idx].default_uint_value)); } FileSpec ModuleListProperties::GetClangModulesCachePath() const { diff --git a/contrib/llvm-project/lldb/source/Core/PluginManager.cpp b/contrib/llvm-project/lldb/source/Core/PluginManager.cpp index b428370d7f33..759ef3a8afe0 100644 --- a/contrib/llvm-project/lldb/source/Core/PluginManager.cpp +++ b/contrib/llvm-project/lldb/source/Core/PluginManager.cpp @@ -12,6 +12,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/SaveCoreOptions.h" #include "lldb/Target/Process.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" @@ -639,6 +640,18 @@ static ObjectFileInstances &GetObjectFileInstances() { return g_instances; } +bool PluginManager::IsRegisteredObjectFilePluginName(llvm::StringRef name) { + if (name.empty()) + return false; + + const auto &instances = GetObjectFileInstances().GetInstances(); + for (auto &instance : instances) { + if (instance.name == name) + return true; + } + return false; +} + bool PluginManager::RegisterPlugin( llvm::StringRef name, llvm::StringRef description, ObjectFileCreateInstance create_callback, @@ -689,12 +702,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName( } Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, - lldb::SaveCoreStyle &core_style, - llvm::StringRef plugin_name) { - if (plugin_name.empty()) { + const lldb_private::SaveCoreOptions &options) { + Status error; + if (!options.GetOutputFile()) { + error.SetErrorString("No output file specified"); + return error; + } + + if (!process_sp) { + error.SetErrorString("Invalid process"); + return error; + } + + if (!options.GetPluginName().has_value()) { // Try saving core directly from the process plugin first. - llvm::Expected<bool> ret = process_sp->SaveCore(outfile.GetPath()); + llvm::Expected<bool> ret = + process_sp->SaveCore(options.GetOutputFile()->GetPath()); if (!ret) return Status(ret.takeError()); if (ret.get()) @@ -702,17 +725,20 @@ Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, } // Fall back to object plugins. - Status error; + const auto &plugin_name = options.GetPluginName().value_or(""); auto &instances = GetObjectFileInstances().GetInstances(); for (auto &instance : instances) { if (plugin_name.empty() || instance.name == plugin_name) { - if (instance.save_core && - instance.save_core(process_sp, outfile, core_style, error)) + if (instance.save_core && instance.save_core(process_sp, options, error)) return error; } } - error.SetErrorString( - "no ObjectFile plugins were able to save a core for this process"); + + // Check to see if any of the object file plugins tried and failed to save. + // If none ran, set the error message. + if (error.Success()) + error.SetErrorString( + "no ObjectFile plugins were able to save a core for this process"); return error; } diff --git a/contrib/llvm-project/lldb/source/Core/Progress.cpp b/contrib/llvm-project/lldb/source/Core/Progress.cpp index 355d6952e53c..1a779e2ddf92 100644 --- a/contrib/llvm-project/lldb/source/Core/Progress.cpp +++ b/contrib/llvm-project/lldb/source/Core/Progress.cpp @@ -11,6 +11,8 @@ #include "lldb/Core/Debugger.h" #include "lldb/Utility/StreamString.h" +#include <cstdint> +#include <mutex> #include <optional> using namespace lldb; @@ -21,16 +23,22 @@ std::atomic<uint64_t> Progress::g_id(0); Progress::Progress(std::string title, std::string details, std::optional<uint64_t> total, lldb_private::Debugger *debugger) - : m_title(title), m_details(details), m_id(++g_id), m_completed(0), - m_total(1) { - assert(total == std::nullopt || total > 0); + : m_details(details), m_completed(0), + m_total(Progress::kNonDeterministicTotal), + m_progress_data{title, ++g_id, + /*m_progress_data.debugger_id=*/std::nullopt} { if (total) m_total = *total; if (debugger) - m_debugger_id = debugger->GetID(); + m_progress_data.debugger_id = debugger->GetID(); + std::lock_guard<std::mutex> guard(m_mutex); ReportProgress(); + + // Report to the ProgressManager if that subsystem is enabled. + if (ProgressManager::Enabled()) + ProgressManager::Instance().Increment(m_progress_data); } Progress::~Progress() { @@ -40,6 +48,10 @@ Progress::~Progress() { if (!m_completed) m_completed = m_total; ReportProgress(); + + // Report to the ProgressManager if that subsystem is enabled. + if (ProgressManager::Enabled()) + ProgressManager::Instance().Decrement(m_progress_data); } void Progress::Increment(uint64_t amount, @@ -49,7 +61,7 @@ void Progress::Increment(uint64_t amount, if (updated_detail) m_details = std::move(updated_detail.value()); // Watch out for unsigned overflow and make sure we don't increment too - // much and exceed m_total. + // much and exceed the total. if (m_total && (amount > (m_total - m_completed))) m_completed = m_total; else @@ -63,7 +75,119 @@ void Progress::ReportProgress() { // Make sure we only send one notification that indicates the progress is // complete m_complete = m_completed == m_total; - Debugger::ReportProgress(m_id, m_title, m_details, m_completed, m_total, - m_debugger_id); + Debugger::ReportProgress(m_progress_data.progress_id, m_progress_data.title, + m_details, m_completed, m_total, + m_progress_data.debugger_id); + } +} + +ProgressManager::ProgressManager() + : m_entries(), m_alarm(std::chrono::milliseconds(100)) {} + +ProgressManager::~ProgressManager() {} + +void ProgressManager::Initialize() { + assert(!InstanceImpl() && "Already initialized."); + InstanceImpl().emplace(); +} + +void ProgressManager::Terminate() { + assert(InstanceImpl() && "Already terminated."); + InstanceImpl().reset(); +} + +bool ProgressManager::Enabled() { return InstanceImpl().operator bool(); } + +ProgressManager &ProgressManager::Instance() { + assert(InstanceImpl() && "ProgressManager must be initialized"); + return *InstanceImpl(); +} + +std::optional<ProgressManager> &ProgressManager::InstanceImpl() { + static std::optional<ProgressManager> g_progress_manager; + return g_progress_manager; +} + +void ProgressManager::Increment(const Progress::ProgressData &progress_data) { + std::lock_guard<std::mutex> lock(m_entries_mutex); + + llvm::StringRef key = progress_data.title; + bool new_entry = !m_entries.contains(key); + Entry &entry = m_entries[progress_data.title]; + + if (new_entry) { + // This is a new progress event. Report progress and store the progress + // data. + ReportProgress(progress_data, EventType::Begin); + entry.data = progress_data; + } else if (entry.refcount == 0) { + // This is an existing entry that was scheduled to be deleted but a new one + // came in before the timer expired. + assert(entry.handle != Alarm::INVALID_HANDLE); + + if (!m_alarm.Cancel(entry.handle)) { + // The timer expired before we had a chance to cancel it. We have to treat + // this as an entirely new progress event. + ReportProgress(progress_data, EventType::Begin); + } + // Clear the alarm handle. + entry.handle = Alarm::INVALID_HANDLE; + } + + // Regardless of how we got here, we need to bump the reference count. + entry.refcount++; +} + +void ProgressManager::Decrement(const Progress::ProgressData &progress_data) { + std::lock_guard<std::mutex> lock(m_entries_mutex); + llvm::StringRef key = progress_data.title; + + if (!m_entries.contains(key)) + return; + + Entry &entry = m_entries[key]; + entry.refcount--; + + if (entry.refcount == 0) { + assert(entry.handle == Alarm::INVALID_HANDLE); + + // Copy the key to a std::string so we can pass it by value to the lambda. + // The underlying StringRef will not exist by the time the callback is + // called. + std::string key_str = std::string(key); + + // Start a timer. If it expires before we see another progress event, it + // will be reported. + entry.handle = m_alarm.Create([=]() { Expire(key_str); }); } } + +void ProgressManager::ReportProgress( + const Progress::ProgressData &progress_data, EventType type) { + // The category bit only keeps track of when progress report categories have + // started and ended, so clear the details and reset other fields when + // broadcasting to it since that bit doesn't need that information. + const uint64_t completed = + (type == EventType::Begin) ? 0 : Progress::kNonDeterministicTotal; + Debugger::ReportProgress(progress_data.progress_id, progress_data.title, "", + completed, Progress::kNonDeterministicTotal, + progress_data.debugger_id, + lldb::eBroadcastBitProgressCategory); +} + +void ProgressManager::Expire(llvm::StringRef key) { + std::lock_guard<std::mutex> lock(m_entries_mutex); + + // This shouldn't happen but be resilient anyway. + if (!m_entries.contains(key)) + return; + + // A new event came in and the alarm fired before we had a chance to restart + // it. + if (m_entries[key].refcount != 0) + return; + + // We're done with this entry. + ReportProgress(m_entries[key].data, EventType::End); + m_entries.erase(key); +} diff --git a/contrib/llvm-project/lldb/source/Core/Section.cpp b/contrib/llvm-project/lldb/source/Core/Section.cpp index 9e98b59deb03..0763e88d4608 100644 --- a/contrib/llvm-project/lldb/source/Core/Section.cpp +++ b/contrib/llvm-project/lldb/source/Core/Section.cpp @@ -275,7 +275,7 @@ bool Section::ContainsFileAddress(addr_t vm_addr) const { void Section::Dump(llvm::raw_ostream &s, unsigned indent, Target *target, uint32_t depth) const { s.indent(indent); - s << llvm::format("0x%8.8" PRIx64 " %-16s ", GetID(), GetTypeAsCString()); + s << llvm::format("0x%16.16" PRIx64 " %-22s ", GetID(), GetTypeAsCString()); bool resolved = true; addr_t addr = LLDB_INVALID_ADDRESS; @@ -642,14 +642,12 @@ void SectionList::Dump(llvm::raw_ostream &s, unsigned indent, Target *target, if (show_header && !m_sections.empty()) { s.indent(indent); s << llvm::formatv( - "SectID Type {0} Address " - " Perm File Off. File Size Flags " - " Section Name\n", + "SectID Type {0} Address " + " Perm File Off. File Size Flags Section Name\n", target_has_loaded_sections ? "Load" : "File"); s.indent(indent); - s << "---------- ---------------- " - "--------------------------------------- ---- ---------- " - "---------- " + s << "------------------ ---------------------- " + "--------------------------------------- ---- ---------- ---------- " "---------- ----------------------------\n"; } diff --git a/contrib/llvm-project/lldb/source/Core/SourceManager.cpp b/contrib/llvm-project/lldb/source/Core/SourceManager.cpp index 517a4b0268d2..0d70c554e534 100644 --- a/contrib/llvm-project/lldb/source/Core/SourceManager.cpp +++ b/contrib/llvm-project/lldb/source/Core/SourceManager.cpp @@ -418,7 +418,7 @@ bool SourceManager::GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line) { if (sc.function->GetAddressRange() .GetBaseAddress() .CalculateSymbolContextLineEntry(line_entry)) { - SetDefaultFileAndLine(line_entry.file, line_entry.line); + SetDefaultFileAndLine(line_entry.GetFile(), line_entry.line); file_spec = m_last_file_spec; line = m_last_line; return true; diff --git a/contrib/llvm-project/lldb/source/Core/ThreadedCommunication.cpp b/contrib/llvm-project/lldb/source/Core/ThreadedCommunication.cpp index 7d8aae5d8ff6..2f3dada3ac93 100644 --- a/contrib/llvm-project/lldb/source/Core/ThreadedCommunication.cpp +++ b/contrib/llvm-project/lldb/source/Core/ThreadedCommunication.cpp @@ -32,8 +32,8 @@ using namespace lldb; using namespace lldb_private; -ConstString &ThreadedCommunication::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.communication"); +llvm::StringRef ThreadedCommunication::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.communication"); return class_name; } diff --git a/contrib/llvm-project/lldb/source/Core/ValueObject.cpp b/contrib/llvm-project/lldb/source/Core/ValueObject.cpp index d58bf2ca763d..8f72efc2299b 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObject.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObject.cpp @@ -216,7 +216,7 @@ bool ValueObject::UpdateFormatsIfNeeded() { m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); any_change = true; - SetValueFormat(DataVisualization::GetFormat(*this, eNoDynamicValues)); + SetValueFormat(DataVisualization::GetFormat(*this, GetDynamicValueType())); SetSummaryFormat( DataVisualization::GetSummaryFormat(*this, GetDynamicValueType())); SetSyntheticChildren( @@ -372,17 +372,17 @@ bool ValueObject::IsLogicalTrue(Status &error) { return ret; } -ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) { +ValueObjectSP ValueObject::GetChildAtIndex(uint32_t idx, bool can_create) { ValueObjectSP child_sp; // We may need to update our value if we are dynamic if (IsPossibleDynamicType()) UpdateValueIfNeeded(false); - if (idx < GetNumChildren()) { + if (idx < GetNumChildrenIgnoringErrors()) { // Check if we have already made the child value object? if (can_create && !m_children.HasChildAtIndex(idx)) { // No we haven't created the child at this index, so lets have our // subclass do it and cache the result for quick future access. - m_children.SetChildAtIndex(idx, CreateChildAtIndex(idx, false, 0)); + m_children.SetChildAtIndex(idx, CreateChildAtIndex(idx)); } ValueObject *child = m_children.GetChildAtIndex(idx); @@ -440,7 +440,7 @@ ValueObjectSP ValueObject::GetChildMemberWithName(llvm::StringRef name, return child_sp; } -size_t ValueObject::GetNumChildren(uint32_t max) { +llvm::Expected<uint32_t> ValueObject::GetNumChildren(uint32_t max) { UpdateValueIfNeeded(); if (max < UINT32_MAX) { @@ -452,11 +452,24 @@ size_t ValueObject::GetNumChildren(uint32_t max) { } if (!m_flags.m_children_count_valid) { - SetNumChildren(CalculateNumChildren()); + auto num_children_or_err = CalculateNumChildren(); + if (num_children_or_err) + SetNumChildren(*num_children_or_err); + else + return num_children_or_err; } return m_children.GetChildrenCount(); } +uint32_t ValueObject::GetNumChildrenIgnoringErrors(uint32_t max) { + auto value_or_err = GetNumChildren(max); + if (value_or_err) + return *value_or_err; + LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(), + "{0}"); + return 0; +} + bool ValueObject::MightHaveChildren() { bool has_children = false; const uint32_t type_info = GetTypeInfo(); @@ -464,25 +477,21 @@ bool ValueObject::MightHaveChildren() { if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference)) has_children = true; } else { - has_children = GetNumChildren() > 0; + has_children = GetNumChildrenIgnoringErrors() > 0; } return has_children; } // Should only be called by ValueObject::GetNumChildren() -void ValueObject::SetNumChildren(size_t num_children) { +void ValueObject::SetNumChildren(uint32_t num_children) { m_flags.m_children_count_valid = true; m_children.SetChildrenCount(num_children); } -ValueObject *ValueObject::CreateChildAtIndex(size_t idx, - bool synthetic_array_member, - int32_t synthetic_index) { - ValueObject *valobj = nullptr; - +ValueObject *ValueObject::CreateChildAtIndex(size_t idx) { bool omit_empty_base_classes = true; - bool ignore_array_bounds = synthetic_array_member; - std::string child_name_str; + bool ignore_array_bounds = false; + std::string child_name; uint32_t child_byte_size = 0; int32_t child_byte_offset = 0; uint32_t child_bitfield_bit_size = 0; @@ -490,43 +499,74 @@ ValueObject *ValueObject::CreateChildAtIndex(size_t idx, bool child_is_base_class = false; bool child_is_deref_of_parent = false; uint64_t language_flags = 0; + const bool transparent_pointers = true; + + ExecutionContext exe_ctx(GetExecutionContextRef()); + + auto child_compiler_type_or_err = + GetCompilerType().GetChildCompilerTypeAtIndex( + &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, this, language_flags); + if (!child_compiler_type_or_err || !child_compiler_type_or_err->IsValid()) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), + child_compiler_type_or_err.takeError(), + "could not find child: {0}"); + return nullptr; + } - const bool transparent_pointers = !synthetic_array_member; - CompilerType child_compiler_type; + return new ValueObjectChild( + *this, *child_compiler_type_or_err, ConstString(child_name), + child_byte_size, child_byte_offset, child_bitfield_bit_size, + child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, + eAddressTypeInvalid, language_flags); +} + +ValueObject *ValueObject::CreateSyntheticArrayMember(size_t idx) { + bool omit_empty_base_classes = true; + bool ignore_array_bounds = true; + std::string child_name; + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class = false; + bool child_is_deref_of_parent = false; + uint64_t language_flags = 0; + const bool transparent_pointers = false; ExecutionContext exe_ctx(GetExecutionContextRef()); - child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex( - &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, - child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, this, language_flags); - if (child_compiler_type) { - if (synthetic_index) - child_byte_offset += child_byte_size * synthetic_index; + auto child_compiler_type_or_err = + GetCompilerType().GetChildCompilerTypeAtIndex( + &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, this, language_flags); + if (!child_compiler_type_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), + child_compiler_type_or_err.takeError(), + "could not find child: {0}"); + return nullptr; + } - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); + if (child_compiler_type_or_err->IsValid()) { + child_byte_offset += child_byte_size * idx; - valobj = new ValueObjectChild( - *this, child_compiler_type, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, - language_flags); + return new ValueObjectChild( + *this, *child_compiler_type_or_err, ConstString(child_name), + child_byte_size, child_byte_offset, child_bitfield_bit_size, + child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, eAddressTypeInvalid, language_flags); } // In case of an incomplete type, try to use the ValueObject's // synthetic value to create the child ValueObject. - if (!valobj && synthetic_array_member) { - if (ValueObjectSP synth_valobj_sp = GetSyntheticValue()) { - valobj = synth_valobj_sp - ->GetChildAtIndex(synthetic_index, synthetic_array_member) - .get(); - } - } + if (ValueObjectSP synth_valobj_sp = GetSyntheticValue()) + return synth_valobj_sp->GetChildAtIndex(idx, /*can_create=*/true).get(); - return valobj; + return nullptr; } bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, @@ -949,41 +989,46 @@ ValueObject::ReadPointedString(lldb::WritableDataBufferSP &buffer_sp, return {total_bytes_read, was_capped}; } -const char *ValueObject::GetObjectDescription() { +llvm::Expected<std::string> ValueObject::GetObjectDescription() { if (!UpdateValueIfNeeded(true)) - return nullptr; + return llvm::createStringError("could not update value"); // Return cached value. if (!m_object_desc_str.empty()) - return m_object_desc_str.c_str(); + return m_object_desc_str; ExecutionContext exe_ctx(GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); if (!process) - return nullptr; + return llvm::createStringError("no process"); // Returns the object description produced by one language runtime. - auto get_object_description = [&](LanguageType language) -> const char * { + auto get_object_description = + [&](LanguageType language) -> llvm::Expected<std::string> { if (LanguageRuntime *runtime = process->GetLanguageRuntime(language)) { StreamString s; - if (runtime->GetObjectDescription(s, *this)) { - m_object_desc_str.append(std::string(s.GetString())); - return m_object_desc_str.c_str(); - } + if (llvm::Error error = runtime->GetObjectDescription(s, *this)) + return error; + m_object_desc_str = s.GetString(); + return m_object_desc_str; } - return nullptr; + return llvm::createStringError("no native language runtime"); }; // Try the native language runtime first. LanguageType native_language = GetObjectRuntimeLanguage(); - if (const char *desc = get_object_description(native_language)) + llvm::Expected<std::string> desc = get_object_description(native_language); + if (desc) return desc; // Try the Objective-C language runtime. This fallback is necessary // for Objective-C++ and mixed Objective-C / C++ programs. - if (Language::LanguageIsCFamily(native_language)) + if (Language::LanguageIsCFamily(native_language)) { + // We're going to try again, so let's drop the first error. + llvm::consumeError(desc.takeError()); return get_object_description(eLanguageTypeObjC); - return nullptr; + } + return desc; } bool ValueObject::GetValueAsCString(const lldb_private::TypeFormatImpl &format, @@ -1076,6 +1121,153 @@ int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { return fail_value; } +llvm::Expected<llvm::APSInt> ValueObject::GetValueAsAPSInt() { + // Make sure the type can be converted to an APSInt. + if (!GetCompilerType().IsInteger() && + !GetCompilerType().IsScopedEnumerationType() && + !GetCompilerType().IsEnumerationType() && + !GetCompilerType().IsPointerType() && + !GetCompilerType().IsNullPtrType() && + !GetCompilerType().IsReferenceType() && !GetCompilerType().IsBoolean()) + return llvm::make_error<llvm::StringError>( + "type cannot be converted to APSInt", llvm::inconvertibleErrorCode()); + + if (CanProvideValue()) { + Scalar scalar; + if (ResolveValue(scalar)) + return scalar.GetAPSInt(); + } + + return llvm::make_error<llvm::StringError>( + "error occurred; unable to convert to APSInt", + llvm::inconvertibleErrorCode()); +} + +llvm::Expected<llvm::APFloat> ValueObject::GetValueAsAPFloat() { + if (!GetCompilerType().IsFloat()) + return llvm::make_error<llvm::StringError>( + "type cannot be converted to APFloat", llvm::inconvertibleErrorCode()); + + if (CanProvideValue()) { + Scalar scalar; + if (ResolveValue(scalar)) + return scalar.GetAPFloat(); + } + + return llvm::make_error<llvm::StringError>( + "error occurred; unable to convert to APFloat", + llvm::inconvertibleErrorCode()); +} + +llvm::Expected<bool> ValueObject::GetValueAsBool() { + CompilerType val_type = GetCompilerType(); + if (val_type.IsInteger() || val_type.IsUnscopedEnumerationType() || + val_type.IsPointerType()) { + auto value_or_err = GetValueAsAPSInt(); + if (value_or_err) + return value_or_err->getBoolValue(); + } + if (val_type.IsFloat()) { + auto value_or_err = GetValueAsAPFloat(); + if (value_or_err) + return value_or_err->isNonZero(); + } + if (val_type.IsArrayType()) + return GetAddressOf() != 0; + + return llvm::make_error<llvm::StringError>("type cannot be converted to bool", + llvm::inconvertibleErrorCode()); +} + +void ValueObject::SetValueFromInteger(const llvm::APInt &value, Status &error) { + // Verify the current object is an integer object + CompilerType val_type = GetCompilerType(); + if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() && + !val_type.IsFloat() && !val_type.IsPointerType() && + !val_type.IsScalarType()) { + error.SetErrorString("current value object is not an integer objet"); + return; + } + + // Verify the current object is not actually associated with any program + // variable. + if (GetVariable()) { + error.SetErrorString("current value object is not a temporary object"); + return; + } + + // Verify the proposed new value is the right size. + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = GetCompilerType().GetByteSize(target.get())) + byte_size = temp.value(); + if (value.getBitWidth() != byte_size * CHAR_BIT) { + error.SetErrorString( + "illegal argument: new value should be of the same size"); + return; + } + + lldb::DataExtractorSP data_sp; + data_sp->SetData(value.getRawData(), byte_size, + target->GetArchitecture().GetByteOrder()); + data_sp->SetAddressByteSize( + static_cast<uint8_t>(target->GetArchitecture().GetAddressByteSize())); + SetData(*data_sp, error); +} + +void ValueObject::SetValueFromInteger(lldb::ValueObjectSP new_val_sp, + Status &error) { + // Verify the current object is an integer object + CompilerType val_type = GetCompilerType(); + if (!val_type.IsInteger() && !val_type.IsUnscopedEnumerationType() && + !val_type.IsFloat() && !val_type.IsPointerType() && + !val_type.IsScalarType()) { + error.SetErrorString("current value object is not an integer objet"); + return; + } + + // Verify the current object is not actually associated with any program + // variable. + if (GetVariable()) { + error.SetErrorString("current value object is not a temporary object"); + return; + } + + // Verify the proposed new value is the right type. + CompilerType new_val_type = new_val_sp->GetCompilerType(); + if (!new_val_type.IsInteger() && !new_val_type.IsFloat() && + !new_val_type.IsPointerType()) { + error.SetErrorString( + "illegal argument: new value should be of the same size"); + return; + } + + if (new_val_type.IsInteger()) { + auto value_or_err = new_val_sp->GetValueAsAPSInt(); + if (value_or_err) + SetValueFromInteger(*value_or_err, error); + else + error.SetErrorString("error getting APSInt from new_val_sp"); + } else if (new_val_type.IsFloat()) { + auto value_or_err = new_val_sp->GetValueAsAPFloat(); + if (value_or_err) + SetValueFromInteger(value_or_err->bitcastToAPInt(), error); + else + error.SetErrorString("error getting APFloat from new_val_sp"); + } else if (new_val_type.IsPointerType()) { + bool success = true; + uint64_t int_val = new_val_sp->GetValueAsUnsigned(0, &success); + if (success) { + lldb::TargetSP target = GetTargetSP(); + uint64_t num_bits = 0; + if (auto temp = new_val_sp->GetCompilerType().GetBitSize(target.get())) + num_bits = temp.value(); + SetValueFromInteger(llvm::APInt(num_bits, int_val), error); + } else + error.SetErrorString("error converting new_val_sp to integer"); + } +} + // if any more "special cases" are added to // ValueObject::DumpPrintableRepresentation() please keep this call up to date // by returning true for your new special cases. We will eventually move to @@ -1176,7 +1368,7 @@ bool ValueObject::DumpPrintableRepresentation( if (flags.Test(eTypeIsArray)) { if ((custom_format == eFormatBytes) || (custom_format == eFormatBytesWithASCII)) { - const size_t count = GetNumChildren(); + const size_t count = GetNumChildrenIgnoringErrors(); s << '['; for (size_t low = 0; low < count; low++) { @@ -1215,7 +1407,7 @@ bool ValueObject::DumpPrintableRepresentation( // format should be printed // directly { - const size_t count = GetNumChildren(); + const size_t count = GetNumChildrenIgnoringErrors(); Format format = FormatManager::GetSingleItemFormat(custom_format); @@ -1285,16 +1477,23 @@ bool ValueObject::DumpPrintableRepresentation( str = GetSummaryAsCString(); break; - case eValueObjectRepresentationStyleLanguageSpecific: - str = GetObjectDescription(); - break; + case eValueObjectRepresentationStyleLanguageSpecific: { + llvm::Expected<std::string> desc = GetObjectDescription(); + if (!desc) { + strm << "error: " << toString(desc.takeError()); + str = strm.GetString(); + } else { + strm << *desc; + str = strm.GetString(); + } + } break; case eValueObjectRepresentationStyleLocation: str = GetLocationAsCString(); break; case eValueObjectRepresentationStyleChildrenCount: - strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren()); + strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildrenIgnoringErrors()); str = strm.GetString(); break; @@ -1312,6 +1511,8 @@ bool ValueObject::DumpPrintableRepresentation( break; } + // If the requested display style produced no output, try falling back to + // alternative presentations. if (str.empty()) { if (val_obj_display == eValueObjectRepresentationStyleValue) str = GetSummaryAsCString(); @@ -1582,64 +1783,62 @@ bool ValueObject::IsUninitializedReference() { ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, bool can_create) { - if (!IsPointerType() && !IsArrayType()) - return ValueObjectSP(); - - std::string index_str = llvm::formatv("[{0}]", index); - ConstString index_const_str(index_str); - // Check if we have already created a synthetic array member in this valid - // object. If we have we will re-use it. - if (auto existing_synthetic_child = GetSyntheticChild(index_const_str)) - return existing_synthetic_child; - - // We haven't made a synthetic array member for INDEX yet, so lets make - // one and cache it for any future reference. - ValueObject *synthetic_child = CreateChildAtIndex(0, true, index); - - if (!synthetic_child) - return ValueObjectSP(); - - // Cache the synthetic child's value because it's valid. - AddSyntheticChild(index_const_str, synthetic_child); - auto synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_flags.m_is_array_item_for_pointer = true; + ValueObjectSP synthetic_child_sp; + if (IsPointerType() || IsArrayType()) { + std::string index_str = llvm::formatv("[{0}]", index); + ConstString index_const_str(index_str); + // Check if we have already created a synthetic array member in this valid + // object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild(index_const_str); + if (!synthetic_child_sp) { + ValueObject *synthetic_child; + // We haven't made a synthetic array member for INDEX yet, so lets make + // one and cache it for any future reference. + synthetic_child = CreateSyntheticArrayMember(index); + + // Cache the value if we got one back... + if (synthetic_child) { + AddSyntheticChild(index_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(ConstString(index_str)); + synthetic_child_sp->m_flags.m_is_array_item_for_pointer = true; + } + } + } return synthetic_child_sp; } ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, bool can_create) { - if (!IsScalarType()) - return ValueObjectSP(); - - std::string index_str = llvm::formatv("[{0}-{1}]", from, to); - ConstString index_const_str(index_str); - - // Check if we have already created a synthetic array member in this valid - // object. If we have we will re-use it. - if (auto existing_synthetic_child = GetSyntheticChild(index_const_str)) - return existing_synthetic_child; - - uint32_t bit_field_size = to - from + 1; - uint32_t bit_field_offset = from; - if (GetDataExtractor().GetByteOrder() == eByteOrderBig) - bit_field_offset = - GetByteSize().value_or(0) * 8 - bit_field_size - bit_field_offset; - - // We haven't made a synthetic array member for INDEX yet, so lets make - // one and cache it for any future reference. - ValueObjectChild *synthetic_child = new ValueObjectChild( - *this, GetCompilerType(), index_const_str, GetByteSize().value_or(0), 0, - bit_field_size, bit_field_offset, false, false, eAddressTypeInvalid, 0); - - if (!synthetic_child) - return ValueObjectSP(); - - // Cache the synthetic child's value because it's valid. - AddSyntheticChild(index_const_str, synthetic_child); - auto synthetic_child_sp = synthetic_child->GetSP(); - synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_flags.m_is_bitfield_for_scalar = true; + ValueObjectSP synthetic_child_sp; + if (IsScalarType()) { + std::string index_str = llvm::formatv("[{0}-{1}]", from, to); + ConstString index_const_str(index_str); + // Check if we have already created a synthetic array member in this valid + // object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild(index_const_str); + if (!synthetic_child_sp) { + uint32_t bit_field_size = to - from + 1; + uint32_t bit_field_offset = from; + if (GetDataExtractor().GetByteOrder() == eByteOrderBig) + bit_field_offset = + GetByteSize().value_or(0) * 8 - bit_field_size - bit_field_offset; + // We haven't made a synthetic array member for INDEX yet, so lets make + // one and cache it for any future reference. + ValueObjectChild *synthetic_child = new ValueObjectChild( + *this, GetCompilerType(), index_const_str, GetByteSize().value_or(0), + 0, bit_field_size, bit_field_offset, false, false, + eAddressTypeInvalid, 0); + + // Cache the value if we got one back... + if (synthetic_child) { + AddSyntheticChild(index_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(ConstString(index_str)); + synthetic_child_sp->m_flags.m_is_bitfield_for_scalar = true; + } + } + } return synthetic_child_sp; } @@ -1649,8 +1848,9 @@ ValueObjectSP ValueObject::GetSyntheticChildAtOffset( ValueObjectSP synthetic_child_sp; - if (name_const_str.IsEmpty()) + if (name_const_str.IsEmpty()) { name_const_str.SetString("@" + std::to_string(offset)); + } // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. @@ -1660,13 +1860,13 @@ ValueObjectSP ValueObject::GetSyntheticChildAtOffset( return synthetic_child_sp; if (!can_create) - return ValueObjectSP(); + return {}; ExecutionContext exe_ctx(GetExecutionContextRef()); std::optional<uint64_t> size = type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!size) - return ValueObjectSP(); + return {}; ValueObjectChild *synthetic_child = new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0, false, false, eAddressTypeInvalid, 0); @@ -1700,7 +1900,7 @@ ValueObjectSP ValueObject::GetSyntheticBase(uint32_t offset, return synthetic_child_sp; if (!can_create) - return ValueObjectSP(); + return {}; const bool is_base_class = true; @@ -1708,7 +1908,7 @@ ValueObjectSP ValueObject::GetSyntheticBase(uint32_t offset, std::optional<uint64_t> size = type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!size) - return ValueObjectSP(); + return {}; ValueObjectChild *synthetic_child = new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0, is_base_class, false, eAddressTypeInvalid, 0); @@ -1737,30 +1937,30 @@ static const char *SkipLeadingExpressionPathSeparators(const char *expression) { ValueObjectSP ValueObject::GetSyntheticExpressionPathChild(const char *expression, bool can_create) { + ValueObjectSP synthetic_child_sp; ConstString name_const_string(expression); // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. - if (auto existing_synthetic_child = GetSyntheticChild(name_const_string)) - return existing_synthetic_child; - - // We haven't made a synthetic array member for expression yet, so lets - // make one and cache it for any future reference. - auto path_options = GetValueForExpressionPathOptions(); - path_options.SetSyntheticChildrenTraversal( - GetValueForExpressionPathOptions::SyntheticChildrenTraversal::None); - auto synthetic_child = - GetValueForExpressionPath(expression, nullptr, nullptr, path_options); - - if (!synthetic_child) - return ValueObjectSP(); - - // Cache the synthetic child's value because it's valid. - // FIXME: this causes a "real" child to end up with its name changed to - // the contents of expression - AddSyntheticChild(name_const_string, synthetic_child.get()); - synthetic_child->SetName( - ConstString(SkipLeadingExpressionPathSeparators(expression))); - return synthetic_child; + synthetic_child_sp = GetSyntheticChild(name_const_string); + if (!synthetic_child_sp) { + // We haven't made a synthetic array member for expression yet, so lets + // make one and cache it for any future reference. + synthetic_child_sp = GetValueForExpressionPath( + expression, nullptr, nullptr, + GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal( + GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: + None)); + + // Cache the value if we got one back... + if (synthetic_child_sp.get()) { + // FIXME: this causes a "real" child to end up with its name changed to + // the contents of expression + AddSyntheticChild(name_const_string, synthetic_child_sp.get()); + synthetic_child_sp->SetName( + ConstString(SkipLeadingExpressionPathSeparators(expression))); + } + } + return synthetic_child_sp; } void ValueObject::CalculateSyntheticValue() { @@ -1957,55 +2157,66 @@ ValueObjectSP ValueObject::GetValueForExpressionPath( const GetValueForExpressionPathOptions &options, ExpressionPathAftermath *final_task_on_target) { - auto dummy_stop_reason = eExpressionPathScanEndReasonUnknown; - auto dummy_value_type = eExpressionPathEndResultTypeInvalid; - auto dummy_final_task = eExpressionPathAftermathNothing; - - auto proxy_stop_reason = reason_to_stop ? reason_to_stop : &dummy_stop_reason; - auto proxy_value_type = - final_value_type ? final_value_type : &dummy_value_type; - auto proxy_final_task = - final_task_on_target ? final_task_on_target : &dummy_final_task; - - auto ret_value = GetValueForExpressionPath_Impl(expression, proxy_stop_reason, - proxy_value_type, options, - proxy_final_task); - - // The caller knows nothing happened if `final_task_on_target` doesn't change. - if (!ret_value || (*proxy_value_type) != eExpressionPathEndResultTypePlain || - !final_task_on_target) - return ValueObjectSP(); - - ExpressionPathAftermath &final_task_on_target_ref = (*final_task_on_target); - ExpressionPathScanEndReason stop_reason_for_error; - Status error; - // The method can only dereference and take the address of plain objects. - switch (final_task_on_target_ref) { - case eExpressionPathAftermathNothing: - return ret_value; - - case eExpressionPathAftermathDereference: - ret_value = ret_value->Dereference(error); - stop_reason_for_error = eExpressionPathScanEndReasonDereferencingFailed; - break; - - case eExpressionPathAftermathTakeAddress: - ret_value = ret_value->AddressOf(error); - stop_reason_for_error = eExpressionPathScanEndReasonTakingAddressFailed; - break; - } - - if (ret_value && error.Success()) { - final_task_on_target_ref = eExpressionPathAftermathNothing; - return ret_value; + ExpressionPathScanEndReason dummy_reason_to_stop = + ValueObject::eExpressionPathScanEndReasonUnknown; + ExpressionPathEndResultType dummy_final_value_type = + ValueObject::eExpressionPathEndResultTypeInvalid; + ExpressionPathAftermath dummy_final_task_on_target = + ValueObject::eExpressionPathAftermathNothing; + + ValueObjectSP ret_val = GetValueForExpressionPath_Impl( + expression, reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, + final_value_type ? final_value_type : &dummy_final_value_type, options, + final_task_on_target ? final_task_on_target + : &dummy_final_task_on_target); + + if (!final_task_on_target || + *final_task_on_target == ValueObject::eExpressionPathAftermathNothing) + return ret_val; + + if (ret_val.get() && + ((final_value_type ? *final_value_type : dummy_final_value_type) == + eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress + // of plain objects + { + if ((final_task_on_target ? *final_task_on_target + : dummy_final_task_on_target) == + ValueObject::eExpressionPathAftermathDereference) { + Status error; + ValueObjectSP final_value = ret_val->Dereference(error); + if (error.Fail() || !final_value.get()) { + if (reason_to_stop) + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonDereferencingFailed; + if (final_value_type) + *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } else { + if (final_task_on_target) + *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; + return final_value; + } + } + if (*final_task_on_target == + ValueObject::eExpressionPathAftermathTakeAddress) { + Status error; + ValueObjectSP final_value = ret_val->AddressOf(error); + if (error.Fail() || !final_value.get()) { + if (reason_to_stop) + *reason_to_stop = + ValueObject::eExpressionPathScanEndReasonTakingAddressFailed; + if (final_value_type) + *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; + return ValueObjectSP(); + } else { + if (final_task_on_target) + *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; + return final_value; + } + } } - - if (reason_to_stop) - *reason_to_stop = stop_reason_for_error; - - if (final_value_type) - *final_value_type = eExpressionPathEndResultTypeInvalid; - return ValueObjectSP(); + return ret_val; // final_task_on_target will still have its original value, so + // you know I did not do it } ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( @@ -2308,7 +2519,9 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( child_valobj_sp = root->GetSyntheticArrayMember(index, true); if (!child_valobj_sp) if (root->HasSyntheticValue() && - root->GetSyntheticValue()->GetNumChildren() > index) + llvm::expectedToStdOptional( + root->GetSyntheticValue()->GetNumChildren()) + .value_or(0) > index) child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index); if (child_valobj_sp) { @@ -2512,11 +2725,14 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( } } -void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); } +llvm::Error ValueObject::Dump(Stream &s) { + return Dump(s, DumpValueObjectOptions(*this)); +} -void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) { - ValueObjectPrinter printer(this, &s, options); - printer.PrintValueObject(); +llvm::Error ValueObject::Dump(Stream &s, + const DumpValueObjectOptions &options) { + ValueObjectPrinter printer(*this, &s, options); + return printer.PrintValueObject(); } ValueObjectSP ValueObject::CreateConstantValue(ConstString name) { @@ -2597,16 +2813,23 @@ ValueObjectSP ValueObject::Dereference(Status &error) { bool child_is_deref_of_parent = false; const bool transparent_pointers = false; CompilerType compiler_type = GetCompilerType(); - CompilerType child_compiler_type; uint64_t language_flags = 0; ExecutionContext exe_ctx(GetExecutionContextRef()); - child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex( + CompilerType child_compiler_type; + auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex( &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, this, language_flags); + if (!child_compiler_type_or_err) + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), + child_compiler_type_or_err.takeError(), + "could not find child: {0}"); + else + child_compiler_type = *child_compiler_type_or_err; + if (child_compiler_type && child_byte_size) { ConstString child_name; if (!child_name_str.empty()) @@ -2676,47 +2899,39 @@ ValueObjectSP ValueObject::AddressOf(Status &error) { const bool scalar_is_load_address = false; addr_t addr = GetAddressOf(scalar_is_load_address, &address_type); error.Clear(); + if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost) { + switch (address_type) { + case eAddressTypeInvalid: { + StreamString expr_path_strm; + GetExpressionPath(expr_path_strm); + error.SetErrorStringWithFormat("'%s' is not in memory", + expr_path_strm.GetData()); + } break; - StreamString expr_path_strm; - GetExpressionPath(expr_path_strm); - const char *expr_path_str = expr_path_strm.GetData(); - - ExecutionContext exe_ctx(GetExecutionContextRef()); - auto scope = exe_ctx.GetBestExecutionContextScope(); - - if (addr == LLDB_INVALID_ADDRESS) { + case eAddressTypeFile: + case eAddressTypeLoad: { + CompilerType compiler_type = GetCompilerType(); + if (compiler_type) { + std::string name(1, '&'); + name.append(m_name.AsCString("")); + ExecutionContext exe_ctx(GetExecutionContextRef()); + m_addr_of_valobj_sp = ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + compiler_type.GetPointerType(), ConstString(name.c_str()), addr, + eAddressTypeInvalid, m_data.GetAddressByteSize()); + } + } break; + default: + break; + } + } else { + StreamString expr_path_strm; + GetExpressionPath(expr_path_strm); error.SetErrorStringWithFormat("'%s' doesn't have a valid address", - expr_path_str); - return ValueObjectSP(); + expr_path_strm.GetData()); } - switch (address_type) { - case eAddressTypeInvalid: - error.SetErrorStringWithFormat("'%s' is not in memory", expr_path_str); - return ValueObjectSP(); - - case eAddressTypeHost: - error.SetErrorStringWithFormat("'%s' is in host process (LLDB) memory", - expr_path_str); - return ValueObjectSP(); - - case eAddressTypeFile: - case eAddressTypeLoad: { - CompilerType compiler_type = GetCompilerType(); - if (!compiler_type) { - error.SetErrorStringWithFormat("'%s' doesn't have a compiler type", - expr_path_str); - return ValueObjectSP(); - } - - std::string name(1, '&'); - name.append(m_name.AsCString("")); - m_addr_of_valobj_sp = ValueObjectConstResult::Create( - scope, compiler_type.GetPointerType(), ConstString(name.c_str()), addr, - eAddressTypeInvalid, m_data.GetAddressByteSize()); - return m_addr_of_valobj_sp; - } - } + return m_addr_of_valobj_sp; } ValueObjectSP ValueObject::DoCast(const CompilerType &compiler_type) { @@ -2725,8 +2940,19 @@ ValueObjectSP ValueObject::DoCast(const CompilerType &compiler_type) { ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) { // Only allow casts if the original type is equal or larger than the cast - // type. We don't know how to fetch more data for all the ConstResult types, - // so we can't guarantee this will work: + // type, unless we know this is a load address. Getting the size wrong for + // a host side storage could leak lldb memory, so we absolutely want to + // prevent that. We may not always get the right value, for instance if we + // have an expression result value that's copied into a storage location in + // the target may not have copied enough memory. I'm not trying to fix that + // here, I'm just making Cast from a smaller to a larger possible in all the + // cases where that doesn't risk making a Value out of random lldb memory. + // You have to check the ValueObject's Value for the address types, since + // ValueObjects that use live addresses will tell you they fetch data from the + // live address, but once they are made, they actually don't. + // FIXME: Can we make ValueObject's with a live address fetch "more data" from + // the live address if it is still valid? + Status error; CompilerType my_type = GetCompilerType(); @@ -2734,9 +2960,10 @@ ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) { = ExecutionContext(GetExecutionContextRef()) .GetBestExecutionContextScope(); if (compiler_type.GetByteSize(exe_scope) - <= GetCompilerType().GetByteSize(exe_scope)) { + <= GetCompilerType().GetByteSize(exe_scope) + || m_value.GetValueType() == Value::ValueType::LoadAddress) return DoCast(compiler_type); - } + error.SetErrorString("Can only cast to a type that is equal to or smaller " "than the orignal type."); @@ -2778,6 +3005,374 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) { return valobj_sp; } +lldb::addr_t ValueObject::GetLoadAddress() { + lldb::addr_t addr_value = LLDB_INVALID_ADDRESS; + if (auto target_sp = GetTargetSP()) { + const bool scalar_is_load_address = true; + AddressType addr_type; + addr_value = GetAddressOf(scalar_is_load_address, &addr_type); + if (addr_type == eAddressTypeFile) { + lldb::ModuleSP module_sp(GetModule()); + if (!module_sp) + addr_value = LLDB_INVALID_ADDRESS; + else { + Address tmp_addr; + module_sp->ResolveFileAddress(addr_value, tmp_addr); + addr_value = tmp_addr.GetLoadAddress(target_sp.get()); + } + } else if (addr_type == eAddressTypeHost || + addr_type == eAddressTypeInvalid) + addr_value = LLDB_INVALID_ADDRESS; + } + return addr_value; +} + +llvm::Expected<lldb::ValueObjectSP> ValueObject::CastDerivedToBaseType( + CompilerType type, const llvm::ArrayRef<uint32_t> &base_type_indices) { + // Make sure the starting type and the target type are both valid for this + // type of cast; otherwise return the shared pointer to the original + // (unchanged) ValueObject. + if (!type.IsPointerType() && !type.IsReferenceType()) + return llvm::make_error<llvm::StringError>( + "Invalid target type: should be a pointer or a reference", + llvm::inconvertibleErrorCode()); + + CompilerType start_type = GetCompilerType(); + if (start_type.IsReferenceType()) + start_type = start_type.GetNonReferenceType(); + + auto target_record_type = + type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType(); + auto start_record_type = + start_type.IsPointerType() ? start_type.GetPointeeType() : start_type; + + if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType()) + return llvm::make_error<llvm::StringError>( + "Underlying start & target types should be record types", + llvm::inconvertibleErrorCode()); + + if (target_record_type.CompareTypes(start_record_type)) + return llvm::make_error<llvm::StringError>( + "Underlying start & target types should be different", + llvm::inconvertibleErrorCode()); + + if (base_type_indices.empty()) + return llvm::make_error<llvm::StringError>( + "Children sequence must be non-empty", llvm::inconvertibleErrorCode()); + + // Both the starting & target types are valid for the cast, and the list of + // base class indices is non-empty, so we can proceed with the cast. + + lldb::TargetSP target = GetTargetSP(); + // The `value` can be a pointer, but GetChildAtIndex works for pointers too. + lldb::ValueObjectSP inner_value = GetSP(); + + for (const uint32_t i : base_type_indices) + // Create synthetic value if needed. + inner_value = + inner_value->GetChildAtIndex(i, /*can_create_synthetic*/ true); + + // At this point type of `inner_value` should be the dereferenced target + // type. + CompilerType inner_value_type = inner_value->GetCompilerType(); + if (type.IsPointerType()) { + if (!inner_value_type.CompareTypes(type.GetPointeeType())) + return llvm::make_error<llvm::StringError>( + "casted value doesn't match the desired type", + llvm::inconvertibleErrorCode()); + + uintptr_t addr = inner_value->GetLoadAddress(); + llvm::StringRef name = ""; + ExecutionContext exe_ctx(target.get(), false); + return ValueObject::CreateValueObjectFromAddress(name, addr, exe_ctx, type, + /* do deref */ false); + } + + // At this point the target type should be a reference. + if (!inner_value_type.CompareTypes(type.GetNonReferenceType())) + return llvm::make_error<llvm::StringError>( + "casted value doesn't match the desired type", + llvm::inconvertibleErrorCode()); + + return lldb::ValueObjectSP(inner_value->Cast(type.GetNonReferenceType())); +} + +llvm::Expected<lldb::ValueObjectSP> +ValueObject::CastBaseToDerivedType(CompilerType type, uint64_t offset) { + // Make sure the starting type and the target type are both valid for this + // type of cast; otherwise return the shared pointer to the original + // (unchanged) ValueObject. + if (!type.IsPointerType() && !type.IsReferenceType()) + return llvm::make_error<llvm::StringError>( + "Invalid target type: should be a pointer or a reference", + llvm::inconvertibleErrorCode()); + + CompilerType start_type = GetCompilerType(); + if (start_type.IsReferenceType()) + start_type = start_type.GetNonReferenceType(); + + auto target_record_type = + type.IsPointerType() ? type.GetPointeeType() : type.GetNonReferenceType(); + auto start_record_type = + start_type.IsPointerType() ? start_type.GetPointeeType() : start_type; + + if (!target_record_type.IsRecordType() || !start_record_type.IsRecordType()) + return llvm::make_error<llvm::StringError>( + "Underlying start & target types should be record types", + llvm::inconvertibleErrorCode()); + + if (target_record_type.CompareTypes(start_record_type)) + return llvm::make_error<llvm::StringError>( + "Underlying start & target types should be different", + llvm::inconvertibleErrorCode()); + + CompilerType virtual_base; + if (target_record_type.IsVirtualBase(start_record_type, &virtual_base)) { + if (!virtual_base.IsValid()) + return llvm::make_error<llvm::StringError>( + "virtual base should be valid", llvm::inconvertibleErrorCode()); + return llvm::make_error<llvm::StringError>( + llvm::Twine("cannot cast " + start_type.TypeDescription() + " to " + + type.TypeDescription() + " via virtual base " + + virtual_base.TypeDescription()), + llvm::inconvertibleErrorCode()); + } + + // Both the starting & target types are valid for the cast, so we can + // proceed with the cast. + + lldb::TargetSP target = GetTargetSP(); + auto pointer_type = + type.IsPointerType() ? type : type.GetNonReferenceType().GetPointerType(); + + uintptr_t addr = + type.IsPointerType() ? GetValueAsUnsigned(0) : GetLoadAddress(); + + llvm::StringRef name = ""; + ExecutionContext exe_ctx(target.get(), false); + lldb::ValueObjectSP value = ValueObject::CreateValueObjectFromAddress( + name, addr - offset, exe_ctx, pointer_type, /* do_deref */ false); + + if (type.IsPointerType()) + return value; + + // At this point the target type is a reference. Since `value` is a pointer, + // it has to be dereferenced. + Status error; + return value->Dereference(error); +} + +lldb::ValueObjectSP ValueObject::CastToBasicType(CompilerType type) { + bool is_scalar = GetCompilerType().IsScalarType(); + bool is_enum = GetCompilerType().IsEnumerationType(); + bool is_pointer = + GetCompilerType().IsPointerType() || GetCompilerType().IsNullPtrType(); + bool is_float = GetCompilerType().IsFloat(); + bool is_integer = GetCompilerType().IsInteger(); + + if (!type.IsScalarType()) { + m_error.SetErrorString("target type must be a scalar"); + return GetSP(); + } + + if (!is_scalar && !is_enum && !is_pointer) { + m_error.SetErrorString("argument must be a scalar, enum, or pointer"); + return GetSP(); + } + + lldb::TargetSP target = GetTargetSP(); + uint64_t type_byte_size = 0; + uint64_t val_byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) + type_byte_size = temp.value(); + if (auto temp = GetCompilerType().GetByteSize(target.get())) + val_byte_size = temp.value(); + + if (is_pointer) { + if (!type.IsInteger() && !type.IsBoolean()) { + m_error.SetErrorString("target type must be an integer or boolean"); + return GetSP(); + } + if (!type.IsBoolean() && type_byte_size < val_byte_size) { + m_error.SetErrorString( + "target type cannot be smaller than the pointer type"); + return GetSP(); + } + } + + if (type.IsBoolean()) { + if (!is_scalar || is_integer) + return ValueObject::CreateValueObjectFromBool( + target, GetValueAsUnsigned(0) != 0, "result"); + else if (is_scalar && is_float) { + auto float_value_or_err = GetValueAsAPFloat(); + if (float_value_or_err) + return ValueObject::CreateValueObjectFromBool( + target, !float_value_or_err->isZero(), "result"); + else { + m_error.SetErrorStringWithFormat( + "cannot get value as APFloat: %s", + llvm::toString(float_value_or_err.takeError()).c_str()); + return GetSP(); + } + } + } + + if (type.IsInteger()) { + if (!is_scalar || is_integer) { + auto int_value_or_err = GetValueAsAPSInt(); + if (int_value_or_err) { + // Get the value as APSInt and extend or truncate it to the requested + // size. + llvm::APSInt ext = + int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT); + return ValueObject::CreateValueObjectFromAPInt(target, ext, type, + "result"); + } else { + m_error.SetErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str()); + ; + return GetSP(); + } + } else if (is_scalar && is_float) { + llvm::APSInt integer(type_byte_size * CHAR_BIT, !type.IsSigned()); + bool is_exact; + auto float_value_or_err = GetValueAsAPFloat(); + if (float_value_or_err) { + llvm::APFloatBase::opStatus status = + float_value_or_err->convertToInteger( + integer, llvm::APFloat::rmTowardZero, &is_exact); + + // Casting floating point values that are out of bounds of the target + // type is undefined behaviour. + if (status & llvm::APFloatBase::opInvalidOp) { + m_error.SetErrorStringWithFormat( + "invalid type cast detected: %s", + llvm::toString(float_value_or_err.takeError()).c_str()); + return GetSP(); + } + return ValueObject::CreateValueObjectFromAPInt(target, integer, type, + "result"); + } + } + } + + if (type.IsFloat()) { + if (!is_scalar) { + auto int_value_or_err = GetValueAsAPSInt(); + if (int_value_or_err) { + llvm::APSInt ext = + int_value_or_err->extOrTrunc(type_byte_size * CHAR_BIT); + Scalar scalar_int(ext); + llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt( + type.GetCanonicalType().GetBasicTypeEnumeration()); + return ValueObject::CreateValueObjectFromAPFloat(target, f, type, + "result"); + } else { + m_error.SetErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str()); + return GetSP(); + } + } else { + if (is_integer) { + auto int_value_or_err = GetValueAsAPSInt(); + if (int_value_or_err) { + Scalar scalar_int(*int_value_or_err); + llvm::APFloat f = scalar_int.CreateAPFloatFromAPSInt( + type.GetCanonicalType().GetBasicTypeEnumeration()); + return ValueObject::CreateValueObjectFromAPFloat(target, f, type, + "result"); + } else { + m_error.SetErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(int_value_or_err.takeError()).c_str()); + return GetSP(); + } + } + if (is_float) { + auto float_value_or_err = GetValueAsAPFloat(); + if (float_value_or_err) { + Scalar scalar_float(*float_value_or_err); + llvm::APFloat f = scalar_float.CreateAPFloatFromAPFloat( + type.GetCanonicalType().GetBasicTypeEnumeration()); + return ValueObject::CreateValueObjectFromAPFloat(target, f, type, + "result"); + } else { + m_error.SetErrorStringWithFormat( + "cannot get value as APFloat: %s", + llvm::toString(float_value_or_err.takeError()).c_str()); + return GetSP(); + } + } + } + } + + m_error.SetErrorString("Unable to perform requested cast"); + return GetSP(); +} + +lldb::ValueObjectSP ValueObject::CastToEnumType(CompilerType type) { + bool is_enum = GetCompilerType().IsEnumerationType(); + bool is_integer = GetCompilerType().IsInteger(); + bool is_float = GetCompilerType().IsFloat(); + + if (!is_enum && !is_integer && !is_float) { + m_error.SetErrorString("argument must be an integer, a float, or an enum"); + return GetSP(); + } + + if (!type.IsEnumerationType()) { + m_error.SetErrorString("target type must be an enum"); + return GetSP(); + } + + lldb::TargetSP target = GetTargetSP(); + uint64_t byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) + byte_size = temp.value(); + + if (is_float) { + llvm::APSInt integer(byte_size * CHAR_BIT, !type.IsSigned()); + bool is_exact; + auto value_or_err = GetValueAsAPFloat(); + if (value_or_err) { + llvm::APFloatBase::opStatus status = value_or_err->convertToInteger( + integer, llvm::APFloat::rmTowardZero, &is_exact); + + // Casting floating point values that are out of bounds of the target + // type is undefined behaviour. + if (status & llvm::APFloatBase::opInvalidOp) { + m_error.SetErrorStringWithFormat( + "invalid type cast detected: %s", + llvm::toString(value_or_err.takeError()).c_str()); + return GetSP(); + } + return ValueObject::CreateValueObjectFromAPInt(target, integer, type, + "result"); + } else { + m_error.SetErrorString("cannot get value as APFloat"); + return GetSP(); + } + } else { + // Get the value as APSInt and extend or truncate it to the requested size. + auto value_or_err = GetValueAsAPSInt(); + if (value_or_err) { + llvm::APSInt ext = value_or_err->extOrTrunc(byte_size * CHAR_BIT); + return ValueObject::CreateValueObjectFromAPInt(target, ext, type, + "result"); + } else { + m_error.SetErrorStringWithFormat( + "cannot get value as APSInt: %s", + llvm::toString(value_or_err.takeError()).c_str()); + return GetSP(); + } + } + m_error.SetErrorString("Cannot perform requested cast"); + return GetSP(); +} + ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {} ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope, @@ -2963,9 +3558,11 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression( lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress( llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, - CompilerType type) { + CompilerType type, bool do_deref) { if (type) { CompilerType pointer_type(type.GetPointerType()); + if (!do_deref) + pointer_type = type; if (pointer_type) { lldb::DataBufferSP buffer( new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t))); @@ -2974,10 +3571,12 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress( ConstString(name), buffer, exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize())); if (ptr_result_valobj_sp) { - ptr_result_valobj_sp->GetValue().SetValueType( - Value::ValueType::LoadAddress); + if (do_deref) + ptr_result_valobj_sp->GetValue().SetValueType( + Value::ValueType::LoadAddress); Status err; - ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); + if (do_deref) + ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); if (ptr_result_valobj_sp && !name.empty()) ptr_result_valobj_sp->SetName(ConstString(name)); } @@ -3000,6 +3599,66 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromData( return new_value_sp; } +lldb::ValueObjectSP +ValueObject::CreateValueObjectFromAPInt(lldb::TargetSP target, + const llvm::APInt &v, CompilerType type, + llvm::StringRef name) { + ExecutionContext exe_ctx(target.get(), false); + uint64_t byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) + byte_size = temp.value(); + lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>( + reinterpret_cast<const void *>(v.getRawData()), byte_size, + exe_ctx.GetByteOrder(), exe_ctx.GetAddressByteSize()); + return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type); +} + +lldb::ValueObjectSP ValueObject::CreateValueObjectFromAPFloat( + lldb::TargetSP target, const llvm::APFloat &v, CompilerType type, + llvm::StringRef name) { + return CreateValueObjectFromAPInt(target, v.bitcastToAPInt(), type, name); +} + +lldb::ValueObjectSP +ValueObject::CreateValueObjectFromBool(lldb::TargetSP target, bool value, + llvm::StringRef name) { + CompilerType target_type; + if (target) { + for (auto type_system_sp : target->GetScratchTypeSystems()) + if (auto compiler_type = + type_system_sp->GetBasicTypeFromAST(lldb::eBasicTypeBool)) { + target_type = compiler_type; + break; + } + } + ExecutionContext exe_ctx(target.get(), false); + uint64_t byte_size = 0; + if (auto temp = target_type.GetByteSize(target.get())) + byte_size = temp.value(); + lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>( + reinterpret_cast<const void *>(&value), byte_size, exe_ctx.GetByteOrder(), + exe_ctx.GetAddressByteSize()); + return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, + target_type); +} + +lldb::ValueObjectSP ValueObject::CreateValueObjectFromNullptr( + lldb::TargetSP target, CompilerType type, llvm::StringRef name) { + if (!type.IsNullPtrType()) { + lldb::ValueObjectSP ret_val; + return ret_val; + } + uintptr_t zero = 0; + ExecutionContext exe_ctx(target.get(), false); + uint64_t byte_size = 0; + if (auto temp = type.GetByteSize(target.get())) + byte_size = temp.value(); + lldb::DataExtractorSP data_sp = std::make_shared<DataExtractor>( + reinterpret_cast<const void *>(zero), byte_size, exe_ctx.GetByteOrder(), + exe_ctx.GetAddressByteSize()); + return ValueObject::CreateValueObjectFromData(name, *data_sp, exe_ctx, type); +} + ModuleSP ValueObject::GetModule() { ValueObject *root(GetRoot()); if (root != this) diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectCast.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectCast.cpp index 0882d4b36776..c8e316415141 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectCast.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectCast.cpp @@ -41,11 +41,13 @@ ValueObjectCast::~ValueObjectCast() = default; CompilerType ValueObjectCast::GetCompilerTypeImpl() { return m_cast_type; } -size_t ValueObjectCast::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> ValueObjectCast::CalculateNumChildren(uint32_t max) { ExecutionContext exe_ctx(GetExecutionContextRef()); auto children_count = GetCompilerType().GetNumChildren( true, &exe_ctx); - return children_count <= max ? children_count : max; + if (!children_count) + return children_count; + return *children_count <= max ? *children_count : max; } std::optional<uint64_t> ValueObjectCast::GetByteSize() { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectChild.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectChild.cpp index 39067387dc97..c6a97dd1a5cd 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectChild.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectChild.cpp @@ -49,10 +49,12 @@ lldb::ValueType ValueObjectChild::GetValueType() const { return m_parent->GetValueType(); } -size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> ValueObjectChild::CalculateNumChildren(uint32_t max) { ExecutionContext exe_ctx(GetExecutionContextRef()); auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); - return children_count <= max ? children_count : max; + if (!children_count) + return children_count; + return *children_count <= max ? *children_count : max; } static void AdjustForBitfieldness(ConstString &name, diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResult.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResult.cpp index 693da1a551f8..879d3c3f6b03 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResult.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResult.cpp @@ -216,10 +216,13 @@ std::optional<uint64_t> ValueObjectConstResult::GetByteSize() { void ValueObjectConstResult::SetByteSize(size_t size) { m_byte_size = size; } -size_t ValueObjectConstResult::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectConstResult::CalculateNumChildren(uint32_t max) { ExecutionContext exe_ctx(GetExecutionContextRef()); auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); - return children_count <= max ? children_count : max; + if (!children_count) + return children_count; + return *children_count <= max ? *children_count : max; } ConstString ValueObjectConstResult::GetTypeName() { @@ -264,12 +267,6 @@ lldb::addr_t ValueObjectConstResult::GetAddressOf(bool scalar_is_load_address, return m_impl.GetAddressOf(scalar_is_load_address, address_type); } -ValueObject *ValueObjectConstResult::CreateChildAtIndex( - size_t idx, bool synthetic_array_member, int32_t synthetic_index) { - return m_impl.CreateChildAtIndex(idx, synthetic_array_member, - synthetic_index); -} - size_t ValueObjectConstResult::GetPointeeData(DataExtractor &data, uint32_t item_idx, uint32_t item_count) { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultCast.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultCast.cpp index fceb2635f876..bf7a12dc6823 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultCast.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultCast.cpp @@ -44,12 +44,6 @@ lldb::ValueObjectSP ValueObjectConstResultCast::AddressOf(Status &error) { return m_impl.AddressOf(error); } -ValueObject *ValueObjectConstResultCast::CreateChildAtIndex( - size_t idx, bool synthetic_array_member, int32_t synthetic_index) { - return m_impl.CreateChildAtIndex(idx, synthetic_array_member, - synthetic_index); -} - size_t ValueObjectConstResultCast::GetPointeeData(DataExtractor &data, uint32_t item_idx, uint32_t item_count) { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultChild.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultChild.cpp index 36bf11a0b73a..39fc0c9fbb35 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultChild.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultChild.cpp @@ -56,12 +56,6 @@ lldb::addr_t ValueObjectConstResultChild::GetAddressOf( return m_impl.GetAddressOf(scalar_is_load_address, address_type); } -ValueObject *ValueObjectConstResultChild::CreateChildAtIndex( - size_t idx, bool synthetic_array_member, int32_t synthetic_index) { - return m_impl.CreateChildAtIndex(idx, synthetic_array_member, - synthetic_index); -} - size_t ValueObjectConstResultChild::GetPointeeData(DataExtractor &data, uint32_t item_idx, uint32_t item_count) { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultImpl.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultImpl.cpp index e2db3ace1924..2a7c90770076 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultImpl.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectConstResultImpl.cpp @@ -17,6 +17,8 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Scalar.h" #include <string> @@ -44,18 +46,15 @@ lldb::ValueObjectSP ValueObjectConstResultImpl::Dereference(Status &error) { return m_impl_backend->ValueObject::Dereference(error); } -ValueObject *ValueObjectConstResultImpl::CreateChildAtIndex( - size_t idx, bool synthetic_array_member, int32_t synthetic_index) { +ValueObject *ValueObjectConstResultImpl::CreateChildAtIndex(size_t idx) { if (m_impl_backend == nullptr) return nullptr; m_impl_backend->UpdateValueIfNeeded(false); - ValueObjectConstResultChild *valobj = nullptr; - bool omit_empty_base_classes = true; - bool ignore_array_bounds = synthetic_array_member; - std::string child_name_str; + bool ignore_array_bounds = false; + std::string child_name; uint32_t child_byte_size = 0; int32_t child_byte_offset = 0; uint32_t child_bitfield_bit_size = 0; @@ -63,16 +62,14 @@ ValueObject *ValueObjectConstResultImpl::CreateChildAtIndex( bool child_is_base_class = false; bool child_is_deref_of_parent = false; uint64_t language_flags; - - const bool transparent_pointers = !synthetic_array_member; + const bool transparent_pointers = true; CompilerType compiler_type = m_impl_backend->GetCompilerType(); - CompilerType child_compiler_type; ExecutionContext exe_ctx(m_impl_backend->GetExecutionContextRef()); - child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex( + auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex( &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, m_impl_backend, language_flags); @@ -81,32 +78,84 @@ ValueObject *ValueObjectConstResultImpl::CreateChildAtIndex( // ValueObject if that's not the case, but it turns out there // are languages out there which allow zero-size types with // children (e.g. Swift). - if (child_compiler_type) { - if (synthetic_index) - child_byte_offset += child_byte_size * synthetic_index; - - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString(child_name_str.c_str()); - - lldb::addr_t child_live_addr = LLDB_INVALID_ADDRESS; - // Transfer the live address (with offset) to the child. But if - // the parent is a pointer, the live address is where that pointer - // value lives in memory, so the children live addresses aren't - // offsets from that value, they are just other load addresses that - // are recorded in the Value of the child ValueObjects. - if (m_live_address != LLDB_INVALID_ADDRESS) { - if (!compiler_type.IsPointerType()) - child_live_addr = m_live_address + child_byte_offset; - } - valobj = new ValueObjectConstResultChild( - *m_impl_backend, child_compiler_type, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, child_live_addr, - language_flags); + if (!child_compiler_type_or_err || !child_compiler_type_or_err->IsValid()) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), + child_compiler_type_or_err.takeError(), + "could not find child: {0}"); + return nullptr; + } + + lldb::addr_t child_live_addr = LLDB_INVALID_ADDRESS; + // Transfer the live address (with offset) to the child. But if + // the parent is a pointer, the live address is where that pointer + // value lives in memory, so the children live addresses aren't + // offsets from that value, they are just other load addresses that + // are recorded in the Value of the child ValueObjects. + if (m_live_address != LLDB_INVALID_ADDRESS && !compiler_type.IsPointerType()) + child_live_addr = m_live_address + child_byte_offset; + + return new ValueObjectConstResultChild( + *m_impl_backend, *child_compiler_type_or_err, ConstString(child_name), + child_byte_size, child_byte_offset, child_bitfield_bit_size, + child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, + child_live_addr, language_flags); +} + +ValueObject * +ValueObjectConstResultImpl::CreateSyntheticArrayMember(size_t idx) { + if (m_impl_backend == nullptr) + return nullptr; + + m_impl_backend->UpdateValueIfNeeded(false); + + bool omit_empty_base_classes = true; + bool ignore_array_bounds = true; + std::string child_name; + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class = false; + bool child_is_deref_of_parent = false; + uint64_t language_flags; + + const bool transparent_pointers = false; + CompilerType compiler_type = m_impl_backend->GetCompilerType(); + + ExecutionContext exe_ctx(m_impl_backend->GetExecutionContextRef()); + + auto child_compiler_type_or_err = compiler_type.GetChildCompilerTypeAtIndex( + &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, m_impl_backend, language_flags); + // One might think we should check that the size of the children + // is always strictly positive, hence we could avoid creating a + // ValueObject if that's not the case, but it turns out there + // are languages out there which allow zero-size types with + // children (e.g. Swift). + if (!child_compiler_type_or_err || !child_compiler_type_or_err->IsValid()) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types), + child_compiler_type_or_err.takeError(), + "could not find child: {0}"); + return nullptr; } - return valobj; + child_byte_offset += child_byte_size * idx; + + lldb::addr_t child_live_addr = LLDB_INVALID_ADDRESS; + // Transfer the live address (with offset) to the child. But if + // the parent is a pointer, the live address is where that pointer + // value lives in memory, so the children live addresses aren't + // offsets from that value, they are just other load addresses that + // are recorded in the Value of the child ValueObjects. + if (m_live_address != LLDB_INVALID_ADDRESS && !compiler_type.IsPointerType()) + child_live_addr = m_live_address + child_byte_offset; + return new ValueObjectConstResultChild( + *m_impl_backend, *child_compiler_type_or_err, ConstString(child_name), + child_byte_size, child_byte_offset, child_bitfield_bit_size, + child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, + child_live_addr, language_flags); } lldb::ValueObjectSP ValueObjectConstResultImpl::GetSyntheticChildAtOffset( diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectDynamicValue.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectDynamicValue.cpp index e6e30dce9d1e..4695febdf8ca 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -85,12 +85,15 @@ ConstString ValueObjectDynamicValue::GetDisplayTypeName() { return m_parent->GetDisplayTypeName(); } -size_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { const bool success = UpdateValueIfNeeded(false); if (success && m_dynamic_type_info.HasType()) { ExecutionContext exe_ctx(GetExecutionContextRef()); auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); - return children_count <= max ? children_count : max; + if (!children_count) + return children_count; + return *children_count <= max ? *children_count : max; } else return m_parent->GetNumChildren(max); } diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectMemory.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectMemory.cpp index 3f125a7bee8c..f555ab82f441 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectMemory.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectMemory.cpp @@ -126,17 +126,21 @@ ConstString ValueObjectMemory::GetDisplayTypeName() { return m_compiler_type.GetDisplayTypeName(); } -size_t ValueObjectMemory::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> ValueObjectMemory::CalculateNumChildren(uint32_t max) { if (m_type_sp) { auto child_count = m_type_sp->GetNumChildren(true); - return child_count <= max ? child_count : max; + if (!child_count) + return child_count; + return *child_count <= max ? *child_count : max; } ExecutionContext exe_ctx(GetExecutionContextRef()); const bool omit_empty_base_classes = true; auto child_count = m_compiler_type.GetNumChildren(omit_empty_base_classes, &exe_ctx); - return child_count <= max ? child_count : max; + if (!child_count) + return child_count; + return *child_count <= max ? *child_count : max; } std::optional<uint64_t> ValueObjectMemory::GetByteSize() { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectRegister.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectRegister.cpp index c2b84c113473..8b5557a0178b 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectRegister.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectRegister.cpp @@ -74,7 +74,8 @@ ConstString ValueObjectRegisterSet::GetQualifiedTypeName() { return ConstString(); } -size_t ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) { const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx); if (reg_set) { auto reg_count = reg_set->num_registers; @@ -114,17 +115,13 @@ bool ValueObjectRegisterSet::UpdateValue() { return m_error.Success(); } -ValueObject *ValueObjectRegisterSet::CreateChildAtIndex( - size_t idx, bool synthetic_array_member, int32_t synthetic_index) { - ValueObject *valobj = nullptr; +ValueObject *ValueObjectRegisterSet::CreateChildAtIndex(size_t idx) { if (m_reg_ctx_sp && m_reg_set) { - const size_t num_children = GetNumChildren(); - if (idx < num_children) - valobj = new ValueObjectRegister( - *this, m_reg_ctx_sp, - m_reg_ctx_sp->GetRegisterInfoAtIndex(m_reg_set->registers[idx])); + return new ValueObjectRegister( + *this, m_reg_ctx_sp, + m_reg_ctx_sp->GetRegisterInfoAtIndex(m_reg_set->registers[idx])); } - return valobj; + return nullptr; } lldb::ValueObjectSP @@ -220,10 +217,13 @@ ConstString ValueObjectRegister::GetTypeName() { return m_type_name; } -size_t ValueObjectRegister::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectRegister::CalculateNumChildren(uint32_t max) { ExecutionContext exe_ctx(GetExecutionContextRef()); auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); - return children_count <= max ? children_count : max; + if (!children_count) + return children_count; + return *children_count <= max ? *children_count : max; } std::optional<uint64_t> ValueObjectRegister::GetByteSize() { diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 43bc532c4a04..adac1b400705 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -31,9 +31,11 @@ public: DummySyntheticFrontEnd(ValueObject &backend) : SyntheticChildrenFrontEnd(backend) {} - size_t CalculateNumChildren() override { return m_backend.GetNumChildren(); } + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_backend.GetNumChildren(); + } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return m_backend.GetChildAtIndex(idx); } @@ -43,7 +45,9 @@ public: bool MightHaveChildren() override { return m_backend.MightHaveChildren(); } - bool Update() override { return false; } + lldb::ChildCacheState Update() override { + return lldb::ChildCacheState::eRefetch; + } }; ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent, @@ -82,7 +86,8 @@ ConstString ValueObjectSynthetic::GetDisplayTypeName() { return m_parent->GetDisplayTypeName(); } -size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectSynthetic::CalculateNumChildren(uint32_t max) { Log *log = GetLog(LLDBLog::DataFormatters); UpdateValueIfNeeded(); @@ -90,18 +95,23 @@ size_t ValueObjectSynthetic::CalculateNumChildren(uint32_t max) { return m_synthetic_children_count <= max ? m_synthetic_children_count : max; if (max < UINT32_MAX) { - size_t num_children = m_synth_filter_up->CalculateNumChildren(max); + auto num_children = m_synth_filter_up->CalculateNumChildren(max); LLDB_LOGF(log, "[ValueObjectSynthetic::CalculateNumChildren] for VO of name " - "%s and type %s, the filter returned %zu child values", - GetName().AsCString(), GetTypeName().AsCString(), num_children); + "%s and type %s, the filter returned %u child values", + GetName().AsCString(), GetTypeName().AsCString(), + num_children ? *num_children : 0); return num_children; } else { - size_t num_children = (m_synthetic_children_count = - m_synth_filter_up->CalculateNumChildren(max)); + auto num_children_or_err = m_synth_filter_up->CalculateNumChildren(max); + if (!num_children_or_err) { + m_synthetic_children_count = 0; + return num_children_or_err; + } + auto num_children = (m_synthetic_children_count = *num_children_or_err); LLDB_LOGF(log, "[ValueObjectSynthetic::CalculateNumChildren] for VO of name " - "%s and type %s, the filter returned %zu child values", + "%s and type %s, the filter returned %u child values", GetName().AsCString(), GetTypeName().AsCString(), num_children); return num_children; } @@ -177,7 +187,7 @@ bool ValueObjectSynthetic::UpdateValue() { } // let our backend do its update - if (!m_synth_filter_up->Update()) { + if (m_synth_filter_up->Update() == lldb::ChildCacheState::eRefetch) { LLDB_LOGF(log, "[ValueObjectSynthetic::UpdateValue] name=%s, synthetic " "filter said caches are stale - clearing", @@ -234,13 +244,13 @@ bool ValueObjectSynthetic::UpdateValue() { return true; } -lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx, +lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(uint32_t idx, bool can_create) { Log *log = GetLog(LLDBLog::DataFormatters); LLDB_LOGF(log, "[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving " - "child at index %zu", + "child at index %u", GetName().AsCString(), idx); UpdateValueIfNeeded(); @@ -259,7 +269,7 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx, if (can_create && m_synth_filter_up != nullptr) { LLDB_LOGF(log, "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at " - "index %zu not cached and will be created", + "index %u not cached and will be created", GetName().AsCString(), idx); lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx); @@ -267,7 +277,7 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx, LLDB_LOGF( log, "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index " - "%zu created as %p (is " + "%u created as %p (is " "synthetic: %s)", GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()), synth_guy.get() @@ -289,7 +299,7 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx, } else { LLDB_LOGF(log, "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at " - "index %zu not cached and cannot " + "index %u not cached and cannot " "be created (can_create = %s, synth_filter = %p)", GetName().AsCString(), idx, can_create ? "yes" : "no", static_cast<void *>(m_synth_filter_up.get())); @@ -299,7 +309,7 @@ lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(size_t idx, } else { LLDB_LOGF(log, "[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at " - "index %zu cached as %p", + "index %u cached as %p", GetName().AsCString(), idx, static_cast<void *>(valobj)); return valobj->GetSP(); diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectVTable.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectVTable.cpp index 177ae4167a1d..72e198d08c9c 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectVTable.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectVTable.cpp @@ -33,7 +33,9 @@ public: std::optional<uint64_t> GetByteSize() override { return m_addr_size; }; - size_t CalculateNumChildren(uint32_t max) override { return 0; }; + llvm::Expected<uint32_t> CalculateNumChildren(uint32_t max) override { + return 0; + }; ValueType GetValueType() const override { return eValueTypeVTableEntry; }; @@ -159,7 +161,7 @@ std::optional<uint64_t> ValueObjectVTable::GetByteSize() { return std::nullopt; } -size_t ValueObjectVTable::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> ValueObjectVTable::CalculateNumChildren(uint32_t max) { if (UpdateValueIfNeeded(false)) return m_num_vtable_entries <= max ? m_num_vtable_entries : max; return 0; @@ -183,11 +185,7 @@ ConstString ValueObjectVTable::GetDisplayTypeName() { bool ValueObjectVTable::IsInScope() { return GetParent()->IsInScope(); } -ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx, - bool synthetic_array_member, - int32_t synthetic_index) { - if (synthetic_array_member) - return nullptr; +ValueObject *ValueObjectVTable::CreateChildAtIndex(size_t idx) { return new ValueObjectVTableChild(*this, idx, m_addr_size); } diff --git a/contrib/llvm-project/lldb/source/Core/ValueObjectVariable.cpp b/contrib/llvm-project/lldb/source/Core/ValueObjectVariable.cpp index 9f8df847f28a..51eb11d3a189 100644 --- a/contrib/llvm-project/lldb/source/Core/ValueObjectVariable.cpp +++ b/contrib/llvm-project/lldb/source/Core/ValueObjectVariable.cpp @@ -94,16 +94,20 @@ ConstString ValueObjectVariable::GetQualifiedTypeName() { return ConstString(); } -size_t ValueObjectVariable::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ValueObjectVariable::CalculateNumChildren(uint32_t max) { CompilerType type(GetCompilerType()); if (!type.IsValid()) - return 0; + return llvm::make_error<llvm::StringError>("invalid type", + llvm::inconvertibleErrorCode()); ExecutionContext exe_ctx(GetExecutionContextRef()); const bool omit_empty_base_classes = true; auto child_count = type.GetNumChildren(omit_empty_base_classes, &exe_ctx); - return child_count <= max ? child_count : max; + if (!child_count) + return child_count; + return *child_count <= max ? *child_count : max; } std::optional<uint64_t> ValueObjectVariable::GetByteSize() { @@ -160,8 +164,11 @@ bool ValueObjectVariable::UpdateValue() { target); } Value old_value(m_value); - if (expr_list.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, nullptr, - nullptr, m_value, &m_error)) { + llvm::Expected<Value> maybe_value = expr_list.Evaluate( + &exe_ctx, nullptr, loclist_base_load_addr, nullptr, nullptr); + + if (maybe_value) { + m_value = *maybe_value; m_resolved_value = m_value; m_value.SetContext(Value::ContextType::Variable, variable); @@ -242,6 +249,7 @@ bool ValueObjectVariable::UpdateValue() { SetValueIsValid(m_error.Success()); } else { + m_error = maybe_value.takeError(); // could not find location, won't allow editing m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr); } diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp index 5e0965fcdae4..6c83b36e79de 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/FormatCache.cpp @@ -51,14 +51,6 @@ void FormatCache::Entry::Set(lldb::SyntheticChildrenSP synthetic_sp) { m_synthetic_sp = synthetic_sp; } -FormatCache::Entry &FormatCache::GetEntry(ConstString type) { - auto i = m_map.find(type), e = m_map.end(); - if (i != e) - return i->second; - m_map[type] = FormatCache::Entry(); - return m_map[type]; -} - namespace lldb_private { template<> bool FormatCache::Entry::IsCached<lldb::TypeFormatImplSP>() { @@ -76,7 +68,7 @@ template<> bool FormatCache::Entry::IsCached<lldb::SyntheticChildrenSP>() { template <typename ImplSP> bool FormatCache::Get(ConstString type, ImplSP &format_impl_sp) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - auto entry = GetEntry(type); + auto entry = m_entries[type]; if (entry.IsCached<ImplSP>()) { m_cache_hits++; entry.Get(format_impl_sp); @@ -101,21 +93,21 @@ FormatCache::Get<lldb::SyntheticChildrenSP>(ConstString, void FormatCache::Set(ConstString type, lldb::TypeFormatImplSP &format_sp) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - GetEntry(type).Set(format_sp); + m_entries[type].Set(format_sp); } void FormatCache::Set(ConstString type, lldb::TypeSummaryImplSP &summary_sp) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - GetEntry(type).Set(summary_sp); + m_entries[type].Set(summary_sp); } void FormatCache::Set(ConstString type, lldb::SyntheticChildrenSP &synthetic_sp) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - GetEntry(type).Set(synthetic_sp); + m_entries[type].Set(synthetic_sp); } void FormatCache::Clear() { std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_map.clear(); + m_entries.clear(); } diff --git a/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp b/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp index f1f135de32ca..7e19989a8264 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp @@ -9,6 +9,7 @@ #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/LanguageCategory.h" #include "lldb/Interpreter/ScriptInterpreter.h" @@ -91,7 +92,7 @@ static bool GetFormatFromFormatChar(char format_char, Format &format) { } static bool GetFormatFromFormatName(llvm::StringRef format_name, - bool partial_match_ok, Format &format) { + Format &format) { uint32_t i; for (i = 0; i < g_num_format_infos; ++i) { if (format_name.equals_insensitive(g_format_infos[i].format_name)) { @@ -100,13 +101,11 @@ static bool GetFormatFromFormatName(llvm::StringRef format_name, } } - if (partial_match_ok) { - for (i = 0; i < g_num_format_infos; ++i) { - if (llvm::StringRef(g_format_infos[i].format_name) - .starts_with_insensitive(format_name)) { - format = g_format_infos[i].format; - return true; - } + for (i = 0; i < g_num_format_infos; ++i) { + if (llvm::StringRef(g_format_infos[i].format_name) + .starts_with_insensitive(format_name)) { + format = g_format_infos[i].format; + return true; } } format = eFormatInvalid; @@ -124,7 +123,6 @@ void FormatManager::Changed() { } bool FormatManager::GetFormatFromCString(const char *format_cstr, - bool partial_match_ok, lldb::Format &format) { bool success = false; if (format_cstr && format_cstr[0]) { @@ -134,7 +132,7 @@ bool FormatManager::GetFormatFromCString(const char *format_cstr, return true; } - success = GetFormatFromFormatName(format_cstr, partial_match_ok, format); + success = GetFormatFromFormatName(format_cstr, format); } if (!success) format = eFormatInvalid; @@ -179,8 +177,14 @@ void FormatManager::GetPossibleMatches( FormattersMatchCandidate::Flags current_flags, bool root_level) { compiler_type = compiler_type.GetTypeForFormatters(); ConstString type_name(compiler_type.GetTypeName()); + // A ValueObject that couldn't be made correctly won't necessarily have a + // target. We aren't going to find a formatter in this case anyway, so we + // should just exit. + TargetSP target_sp = valobj.GetTargetSP(); + if (!target_sp) + return; ScriptInterpreter *script_interpreter = - valobj.GetTargetSP()->GetDebugger().GetScriptInterpreter(); + target_sp->GetDebugger().GetScriptInterpreter(); if (valobj.GetBitfieldBitSize() > 0) { StreamString sstring; sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize()); @@ -445,17 +449,25 @@ lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) { } bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { + TargetSP target_sp = valobj.GetTargetSP(); // if settings say no oneline whatsoever - if (valobj.GetTargetSP().get() && - !valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries()) + if (target_sp && !target_sp->GetDebugger().GetAutoOneLineSummaries()) return false; // then don't oneline // if this object has a summary, then ask the summary if (valobj.GetSummaryFormat().get() != nullptr) return valobj.GetSummaryFormat()->IsOneLiner(); + const size_t max_num_children = + (target_sp ? *target_sp : Target::GetGlobalProperties()) + .GetMaximumNumberOfChildrenToDisplay(); + auto num_children = valobj.GetNumChildren(max_num_children); + if (!num_children) { + llvm::consumeError(num_children.takeError()); + return true; + } // no children, no party - if (valobj.GetNumChildren() == 0) + if (*num_children == 0) return false; // ask the type if it has any opinion about this eLazyBoolCalculate == no @@ -474,7 +486,7 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { size_t total_children_name_len = 0; - for (size_t idx = 0; idx < valobj.GetNumChildren(); idx++) { + for (size_t idx = 0; idx < *num_children; idx++) { bool is_synth_val = false; ValueObjectSP child_sp(valobj.GetChildAtIndex(idx)); // something is wrong here - bail out @@ -526,7 +538,7 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { } // if this child has children.. - if (child_sp->GetNumChildren()) { + if (child_sp->HasChildren()) { // ...and no summary... // (if it had a summary and the summary wanted children, we would have // bailed out anyway diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp index fd76bab95826..ce2cf369b5be 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -25,19 +25,31 @@ TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst) } void TypeCategoryMap::Add(KeyType name, const TypeCategoryImplSP &entry) { - std::lock_guard<std::recursive_mutex> guard(m_map_mutex); - m_map[name] = entry; + { + std::lock_guard<std::recursive_mutex> guard(m_map_mutex); + m_map[name] = entry; + } + // Release the mutex to avoid a potential deadlock between + // TypeCategoryMap::m_map_mutex and + // FormatManager::m_language_categories_mutex which can be acquired in + // reverse order when calling FormatManager::Changed. if (listener) listener->Changed(); } bool TypeCategoryMap::Delete(KeyType name) { - std::lock_guard<std::recursive_mutex> guard(m_map_mutex); - MapIterator iter = m_map.find(name); - if (iter == m_map.end()) - return false; - m_map.erase(name); - Disable(name); + { + std::lock_guard<std::recursive_mutex> guard(m_map_mutex); + MapIterator iter = m_map.find(name); + if (iter == m_map.end()) + return false; + m_map.erase(name); + Disable(name); + } + // Release the mutex to avoid a potential deadlock between + // TypeCategoryMap::m_map_mutex and + // FormatManager::m_language_categories_mutex which can be acquired in + // reverse order when calling FormatManager::Changed. if (listener) listener->Changed(); return true; @@ -123,9 +135,15 @@ void TypeCategoryMap::DisableAllCategories() { } void TypeCategoryMap::Clear() { - std::lock_guard<std::recursive_mutex> guard(m_map_mutex); - m_map.clear(); - m_active_categories.clear(); + { + std::lock_guard<std::recursive_mutex> guard(m_map_mutex); + m_map.clear(); + m_active_categories.clear(); + } + // Release the mutex to avoid a potential deadlock between + // TypeCategoryMap::m_map_mutex and + // FormatManager::m_language_categories_mutex which can be acquired in + // reverse order when calling FormatManager::Changed. if (listener) listener->Changed(); } diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp index c09ed31d0338..3707d2d879d3 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeSummary.cpp @@ -80,7 +80,10 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, sc = frame->GetSymbolContext(lldb::eSymbolContextEverything); if (IsOneLiner()) { - ValueObjectPrinter printer(valobj, &s, DumpValueObjectOptions()); + // We've already checked the case of a NULL valobj above. Let's put in an + // assert here to make sure someone doesn't take that out: + assert(valobj && "Must have a valid ValueObject to summarize"); + ValueObjectPrinter printer(*valobj, &s, DumpValueObjectOptions()); printer.PrintChildrenOneLiner(HideNames(valobj)); retval = std::string(s.GetString()); return true; diff --git a/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp b/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp index de042e474903..7aa0670190b2 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/TypeSynthetic.cpp @@ -115,6 +115,16 @@ std::string CXXSyntheticChildren::GetDescription() { return std::string(sstr.GetString()); } +uint32_t +SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) { + auto value_or_err = CalculateNumChildren(max); + if (value_or_err) + return *value_or_err; + LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(), + "{0}"); + return 0; +} + lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression( llvm::StringRef name, llvm::StringRef expression, const ExecutionContext &exe_ctx) { @@ -167,7 +177,7 @@ ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default; lldb::ValueObjectSP -ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(size_t idx) { +ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(uint32_t idx) { if (!m_wrapper_sp || !m_interpreter) return lldb::ValueObjectSP(); @@ -178,23 +188,27 @@ bool ScriptedSyntheticChildren::FrontEnd::IsValid() { return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter); } -size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> +ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() { if (!m_wrapper_sp || m_interpreter == nullptr) return 0; return m_interpreter->CalculateNumChildren(m_wrapper_sp, UINT32_MAX); } -size_t ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) { +llvm::Expected<uint32_t> +ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) { if (!m_wrapper_sp || m_interpreter == nullptr) return 0; return m_interpreter->CalculateNumChildren(m_wrapper_sp, max); } -bool ScriptedSyntheticChildren::FrontEnd::Update() { +lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() { if (!m_wrapper_sp || m_interpreter == nullptr) - return false; + return lldb::ChildCacheState::eRefetch; - return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp); + return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp) + ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() { diff --git a/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 074d0b648e6f..ce24a7866e53 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -14,43 +14,41 @@ #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Stream.h" +#include "llvm/Support/MathExtras.h" +#include <cstdint> using namespace lldb; using namespace lldb_private; -ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) { - if (valobj) { - DumpValueObjectOptions options(*valobj); - Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); - } else { - DumpValueObjectOptions options; - Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); - } +ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s) + : m_orig_valobj(valobj) { + DumpValueObjectOptions options(valobj); + Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); } -ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s, - const DumpValueObjectOptions &options) { +ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s, + const DumpValueObjectOptions &options) + : m_orig_valobj(valobj) { Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); } ValueObjectPrinter::ValueObjectPrinter( - ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, + ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options, const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, - InstancePointersSetSP printed_instance_pointers) { + InstancePointersSetSP printed_instance_pointers) + : m_orig_valobj(valobj) { Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers); } void ValueObjectPrinter::Init( - ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, + ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options, const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, InstancePointersSetSP printed_instance_pointers) { - m_orig_valobj = valobj; - m_valobj = nullptr; + m_cached_valobj = nullptr; m_stream = s; m_options = options; m_ptr_depth = ptr_depth; m_curr_depth = curr_depth; - assert(m_orig_valobj && "cannot print a NULL ValueObject"); assert(m_stream && "cannot print to a NULL Stream"); m_should_print = eLazyBoolCalculate; m_is_nil = eLazyBoolCalculate; @@ -68,23 +66,16 @@ void ValueObjectPrinter::Init( printed_instance_pointers ? printed_instance_pointers : InstancePointersSetSP(new InstancePointersSet()); + SetupMostSpecializedValue(); } -bool ValueObjectPrinter::PrintValueObject() { - if (!m_orig_valobj) - return false; - +llvm::Error ValueObjectPrinter::PrintValueObject() { // If the incoming ValueObject is in an error state, the best we're going to // get out of it is its type. But if we don't even have that, just print // the error and exit early. - if (m_orig_valobj->GetError().Fail() - && !m_orig_valobj->GetCompilerType().IsValid()) { - m_stream->Printf("Error: '%s'", m_orig_valobj->GetError().AsCString()); - return true; - } - - if (!GetMostSpecializedValue() || m_valobj == nullptr) - return false; + if (m_orig_valobj.GetError().Fail() && + !m_orig_valobj.GetCompilerType().IsValid()) + return m_orig_valobj.GetError().ToError(); if (ShouldPrintValueObject()) { PrintLocationIfNeeded(); @@ -100,73 +91,82 @@ bool ValueObjectPrinter::PrintValueObject() { PrintValueAndSummaryIfNeeded(value_printed, summary_printed); if (m_val_summary_ok) - PrintChildrenIfNeeded(value_printed, summary_printed); - else - m_stream->EOL(); + return PrintChildrenIfNeeded(value_printed, summary_printed); + m_stream->EOL(); - return true; + return llvm::Error::success(); } -bool ValueObjectPrinter::GetMostSpecializedValue() { - if (m_valobj) - return true; - bool update_success = m_orig_valobj->UpdateValueIfNeeded(true); - if (!update_success) { - m_valobj = m_orig_valobj; - } else { - if (m_orig_valobj->IsDynamic()) { +ValueObject &ValueObjectPrinter::GetMostSpecializedValue() { + assert(m_cached_valobj && "ValueObjectPrinter must have a valid ValueObject"); + return *m_cached_valobj; +} + +void ValueObjectPrinter::SetupMostSpecializedValue() { + bool update_success = m_orig_valobj.UpdateValueIfNeeded(true); + // If we can't find anything better, we'll fall back on the original + // ValueObject. + m_cached_valobj = &m_orig_valobj; + if (update_success) { + if (m_orig_valobj.IsDynamic()) { if (m_options.m_use_dynamic == eNoDynamicValues) { - ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); + ValueObject *static_value = m_orig_valobj.GetStaticValue().get(); if (static_value) - m_valobj = static_value; - else - m_valobj = m_orig_valobj; - } else - m_valobj = m_orig_valobj; + m_cached_valobj = static_value; + } } else { if (m_options.m_use_dynamic != eNoDynamicValues) { ValueObject *dynamic_value = - m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get(); + m_orig_valobj.GetDynamicValue(m_options.m_use_dynamic).get(); if (dynamic_value) - m_valobj = dynamic_value; - else - m_valobj = m_orig_valobj; - } else - m_valobj = m_orig_valobj; + m_cached_valobj = dynamic_value; + } } - if (m_valobj->IsSynthetic()) { + if (m_cached_valobj->IsSynthetic()) { if (!m_options.m_use_synthetic) { - ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); + ValueObject *non_synthetic = + m_cached_valobj->GetNonSyntheticValue().get(); if (non_synthetic) - m_valobj = non_synthetic; + m_cached_valobj = non_synthetic; } } else { if (m_options.m_use_synthetic) { - ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); + ValueObject *synthetic = m_cached_valobj->GetSyntheticValue().get(); if (synthetic) - m_valobj = synthetic; + m_cached_valobj = synthetic; } } } - m_compiler_type = m_valobj->GetCompilerType(); + m_compiler_type = m_cached_valobj->GetCompilerType(); m_type_flags = m_compiler_type.GetTypeInfo(); - return true; + assert(m_cached_valobj && + "SetupMostSpecialized value must compute a valid ValueObject"); } -const char *ValueObjectPrinter::GetDescriptionForDisplay() { - const char *str = m_valobj->GetObjectDescription(); +llvm::Expected<std::string> ValueObjectPrinter::GetDescriptionForDisplay() { + ValueObject &valobj = GetMostSpecializedValue(); + llvm::Expected<std::string> maybe_str = valobj.GetObjectDescription(); + if (maybe_str) + return maybe_str; + + const char *str = nullptr; + if (!str) + str = valobj.GetSummaryAsCString(); if (!str) - str = m_valobj->GetSummaryAsCString(); + str = valobj.GetValueAsCString(); + if (!str) - str = m_valobj->GetValueAsCString(); + return maybe_str; + llvm::consumeError(maybe_str.takeError()); return str; } const char *ValueObjectPrinter::GetRootNameForDisplay() { - const char *root_valobj_name = m_options.m_root_valobj_name.empty() - ? m_valobj->GetName().AsCString() - : m_options.m_root_valobj_name.c_str(); + const char *root_valobj_name = + m_options.m_root_valobj_name.empty() + ? GetMostSpecializedValue().GetName().AsCString() + : m_options.m_root_valobj_name.c_str(); return root_valobj_name ? root_valobj_name : ""; } @@ -181,14 +181,16 @@ bool ValueObjectPrinter::ShouldPrintValueObject() { bool ValueObjectPrinter::IsNil() { if (m_is_nil == eLazyBoolCalculate) - m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo; + m_is_nil = + GetMostSpecializedValue().IsNilReference() ? eLazyBoolYes : eLazyBoolNo; return m_is_nil == eLazyBoolYes; } bool ValueObjectPrinter::IsUninitialized() { if (m_is_uninit == eLazyBoolCalculate) - m_is_uninit = - m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo; + m_is_uninit = GetMostSpecializedValue().IsUninitializedReference() + ? eLazyBoolYes + : eLazyBoolNo; return m_is_uninit == eLazyBoolYes; } @@ -213,19 +215,20 @@ bool ValueObjectPrinter::IsAggregate() { bool ValueObjectPrinter::IsInstancePointer() { // you need to do this check on the value's clang type + ValueObject &valobj = GetMostSpecializedValue(); if (m_is_instance_ptr == eLazyBoolCalculate) - m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() & + m_is_instance_ptr = (valobj.GetValue().GetCompilerType().GetTypeInfo() & eTypeInstanceIsPointer) != 0 ? eLazyBoolYes : eLazyBoolNo; - if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass()) + if ((eLazyBoolYes == m_is_instance_ptr) && valobj.IsBaseClass()) m_is_instance_ptr = eLazyBoolNo; return m_is_instance_ptr == eLazyBoolYes; } bool ValueObjectPrinter::PrintLocationIfNeeded() { if (m_options.m_show_location) { - m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); + m_stream->Printf("%s: ", GetMostSpecializedValue().GetLocationAsCString()); return true; } return false; @@ -244,6 +247,8 @@ void ValueObjectPrinter::PrintDecl() { (m_curr_depth == 0 && !m_options.m_flat_output); StreamString typeName; + // Figure out which ValueObject we're acting on + ValueObject &valobj = GetMostSpecializedValue(); // always show the type at the root level if it is invalid if (show_type) { @@ -252,8 +257,8 @@ void ValueObjectPrinter::PrintDecl() { ConstString type_name; if (m_compiler_type.IsValid()) { type_name = m_options.m_use_type_display_name - ? m_valobj->GetDisplayTypeName() - : m_valobj->GetQualifiedTypeName(); + ? valobj.GetDisplayTypeName() + : valobj.GetQualifiedTypeName(); } else { // only show an invalid type name if the user explicitly triggered // show_type @@ -277,7 +282,7 @@ void ValueObjectPrinter::PrintDecl() { if (ShouldShowName()) { if (m_options.m_flat_output) - m_valobj->GetExpressionPath(varName); + valobj.GetExpressionPath(varName); else varName << GetRootNameForDisplay(); } @@ -289,7 +294,7 @@ void ValueObjectPrinter::PrintDecl() { // one for the ValueObject lldb::LanguageType lang_type = (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) - ? m_valobj->GetPreferredDisplayLanguage() + ? valobj.GetPreferredDisplayLanguage() : m_options.m_varformat_language; if (Language *lang_plugin = Language::FindPlugin(lang_type)) { m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper(); @@ -327,14 +332,15 @@ void ValueObjectPrinter::PrintDecl() { bool ValueObjectPrinter::CheckScopeIfNeeded() { if (m_options.m_scope_already_checked) return true; - return m_valobj->IsInScope(); + return GetMostSpecializedValue().IsInScope(); } TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) { if (!m_summary_formatter.second) { - TypeSummaryImpl *entry = m_options.m_summary_sp - ? m_options.m_summary_sp.get() - : m_valobj->GetSummaryFormat().get(); + TypeSummaryImpl *entry = + m_options.m_summary_sp + ? m_options.m_summary_sp.get() + : GetMostSpecializedValue().GetSummaryFormat().get(); if (m_options.m_omit_summary_depth > 0) entry = nullptr; @@ -357,18 +363,19 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, std::string &summary, std::string &error) { lldb::Format format = m_options.m_format; + ValueObject &valobj = GetMostSpecializedValue(); // if I am printing synthetized elements, apply the format to those elements // only if (m_options.m_pointer_as_array) - m_valobj->GetValueAsCString(lldb::eFormatDefault, value); - else if (format != eFormatDefault && format != m_valobj->GetFormat()) - m_valobj->GetValueAsCString(format, value); + valobj.GetValueAsCString(lldb::eFormatDefault, value); + else if (format != eFormatDefault && format != valobj.GetFormat()) + valobj.GetValueAsCString(format, value); else { - const char *val_cstr = m_valobj->GetValueAsCString(); + const char *val_cstr = valobj.GetValueAsCString(); if (val_cstr) value.assign(val_cstr); } - const char *err_cstr = m_valobj->GetError().AsCString(); + const char *err_cstr = valobj.GetError().AsCString(); if (err_cstr) error.assign(err_cstr); @@ -378,7 +385,7 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, if (IsNil()) { lldb::LanguageType lang_type = (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) - ? m_valobj->GetPreferredDisplayLanguage() + ? valobj.GetPreferredDisplayLanguage() : m_options.m_varformat_language; if (Language *lang_plugin = Language::FindPlugin(lang_type)) { summary.assign(lang_plugin->GetNilReferenceSummaryString().str()); @@ -392,11 +399,11 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, } else if (m_options.m_omit_summary_depth == 0) { TypeSummaryImpl *entry = GetSummaryFormatter(); if (entry) { - m_valobj->GetSummaryAsCString(entry, summary, - m_options.m_varformat_language); + valobj.GetSummaryAsCString(entry, summary, + m_options.m_varformat_language); } else { const char *sum_cstr = - m_valobj->GetSummaryAsCString(m_options.m_varformat_language); + valobj.GetSummaryAsCString(m_options.m_varformat_language); if (sum_cstr) summary.assign(sum_cstr); } @@ -431,16 +438,17 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, // this thing is nil (but show the value if the user passes a format // explicitly) TypeSummaryImpl *entry = GetSummaryFormatter(); + ValueObject &valobj = GetMostSpecializedValue(); const bool has_nil_or_uninitialized_summary = (IsNil() || IsUninitialized()) && !m_summary.empty(); if (!has_nil_or_uninitialized_summary && !m_value.empty() && (entry == nullptr || - (entry->DoesPrintValue(m_valobj) || + (entry->DoesPrintValue(&valobj) || m_options.m_format != eFormatDefault) || m_summary.empty()) && !m_options.m_hide_value) { if (m_options.m_hide_pointer_value && - IsPointerValue(m_valobj->GetCompilerType())) { + IsPointerValue(valobj.GetCompilerType())) { } else { if (ShouldShowName()) m_stream->PutChar(' '); @@ -460,34 +468,38 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, return !error_printed; } -bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, - bool summary_printed) { +llvm::Error +ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, + bool summary_printed) { if (ShouldPrintValueObject()) { // let's avoid the overly verbose no description error for a nil thing if (m_options.m_use_objc && !IsNil() && !IsUninitialized() && (!m_options.m_pointer_as_array)) { if (!m_options.m_hide_value || ShouldShowName()) - m_stream->Printf(" "); - const char *object_desc = nullptr; - if (value_printed || summary_printed) - object_desc = m_valobj->GetObjectDescription(); - else - object_desc = GetDescriptionForDisplay(); - if (object_desc && *object_desc) { + *m_stream << ' '; + llvm::Expected<std::string> object_desc = + (value_printed || summary_printed) + ? GetMostSpecializedValue().GetObjectDescription() + : GetDescriptionForDisplay(); + if (!object_desc) { + // If no value or summary was printed, surface the error. + if (!value_printed && !summary_printed) + return object_desc.takeError(); + // Otherwise gently nudge the user that they should have used + // `p` instead of `po`. Unfortunately we cannot be more direct + // about this, because we don't actually know what the user did. + *m_stream << "warning: no object description available\n"; + llvm::consumeError(object_desc.takeError()); + } else { + *m_stream << *object_desc; // If the description already ends with a \n don't add another one. - size_t object_end = strlen(object_desc) - 1; - if (object_desc[object_end] == '\n') - m_stream->Printf("%s", object_desc); - else - m_stream->Printf("%s\n", object_desc); - return true; - } else if (!value_printed && !summary_printed) - return true; - else - return false; + if (object_desc->empty() || object_desc->back() != '\n') + *m_stream << '\n'; + } + return llvm::Error::success(); } } - return true; + return llvm::Error::success(); } bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const { @@ -523,8 +535,9 @@ bool ValueObjectPrinter::ShouldPrintChildren( return false; bool print_children = true; + ValueObject &valobj = GetMostSpecializedValue(); if (TypeSummaryImpl *type_summary = GetSummaryFormatter()) - print_children = type_summary->DoesPrintChildren(m_valobj); + print_children = type_summary->DoesPrintChildren(&valobj); // We will show children for all concrete types. We won't show pointer // contents unless a pointer depth has been specified. We won't reference @@ -537,7 +550,7 @@ bool ValueObjectPrinter::ShouldPrintChildren( // We have a pointer or reference whose value is an address. Make sure // that address is not NULL AddressType ptr_address_type; - if (m_valobj->GetPointerValue(&ptr_address_type) == 0) + if (valobj.GetPointerValue(&ptr_address_type) == 0) return false; const bool is_root_level = m_curr_depth == 0; @@ -565,8 +578,8 @@ bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { return entry->DoesPrintEmptyAggregates(); } -ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { - return m_valobj; +ValueObject &ValueObjectPrinter::GetValueObjectForChildrenGeneration() { + return GetMostSpecializedValue(); } void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed, @@ -612,37 +625,48 @@ void ValueObjectPrinter::PrintChild( if (does_consume_ptr_depth) ptr_depth = curr_ptr_depth.Decremented(); - ValueObjectPrinter child_printer(child_sp.get(), m_stream, child_options, + ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options, ptr_depth, m_curr_depth + 1, m_printed_instance_pointers); - child_printer.PrintValueObject(); + llvm::Error error = child_printer.PrintValueObject(); + if (error) { + if (m_stream) + *m_stream << "error: " << toString(std::move(error)); + else + llvm::consumeError(std::move(error)); + } } } -uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { - ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); +llvm::Expected<uint32_t> +ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { + ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); if (m_options.m_pointer_as_array) return m_options.m_pointer_as_array.m_element_count; - size_t num_children = synth_m_valobj->GetNumChildren(); - print_dotdotdot = false; - if (num_children) { - const size_t max_num_children = - m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); - - if (num_children > max_num_children && !m_options.m_ignore_cap) { - print_dotdotdot = true; - return max_num_children; - } + const uint32_t max_num_children = + m_options.m_ignore_cap ? UINT32_MAX + : GetMostSpecializedValue() + .GetTargetSP() + ->GetMaximumNumberOfChildrenToDisplay(); + // Ask for one more child than the maximum to see if we should print "...". + auto num_children_or_err = synth_valobj.GetNumChildren( + llvm::SaturatingAdd(max_num_children, uint32_t(1))); + if (!num_children_or_err) + return num_children_or_err; + if (*num_children_or_err > max_num_children) { + print_dotdotdot = true; + return max_num_children; } - return num_children; + return num_children_or_err; } void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { if (!m_options.m_flat_output) { if (print_dotdotdot) { - m_valobj->GetTargetSP() + GetMostSpecializedValue() + .GetTargetSP() ->GetDebugger() .GetCommandInterpreter() .ChildrenTruncated(); @@ -655,7 +679,7 @@ void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, bool summary_printed) { - ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); + ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); if (!IsAggregate()) return false; @@ -665,7 +689,7 @@ bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, return false; } - if (synth_m_valobj->MightHaveChildren()) + if (synth_valobj.MightHaveChildren()) return true; if (m_val_summary_ok) @@ -679,33 +703,38 @@ static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, return base + logical * stride; } -ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj, +ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject &synth_valobj, size_t idx) { if (m_options.m_pointer_as_array) { // if generating pointer-as-array children, use GetSyntheticArrayMember - return synth_valobj->GetSyntheticArrayMember( + return synth_valobj.GetSyntheticArrayMember( PhysicalIndexForLogicalIndex( m_options.m_pointer_as_array.m_base_element, m_options.m_pointer_as_array.m_stride, idx), true); } else { // otherwise, do the usual thing - return synth_valobj->GetChildAtIndex(idx); + return synth_valobj.GetChildAtIndex(idx); } } void ValueObjectPrinter::PrintChildren( bool value_printed, bool summary_printed, const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { - ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); + ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); bool print_dotdotdot = false; - size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); + auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot); + if (!num_children_or_err) { + *m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>'; + return; + } + uint32_t num_children = *num_children_or_err; if (num_children) { bool any_children_printed = false; for (size_t idx = 0; idx < num_children; ++idx) { - if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { + if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) { if (m_options.m_child_printing_decider && !m_options.m_child_printing_decider(child_sp->GetName())) continue; @@ -733,7 +762,7 @@ void ValueObjectPrinter::PrintChildren( if (ShouldPrintValueObject()) { // if it has a synthetic value, then don't print {}, the synthetic // children are probably only being used to vend a value - if (m_valobj->DoesProvideSyntheticValue() || + if (GetMostSpecializedValue().DoesProvideSyntheticValue() || !ShouldExpandEmptyAggregates()) m_stream->PutCString("\n"); else @@ -746,20 +775,22 @@ void ValueObjectPrinter::PrintChildren( } bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { - if (!GetMostSpecializedValue() || m_valobj == nullptr) - return false; - - ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); + ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); bool print_dotdotdot = false; - size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); + auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot); + if (!num_children_or_err) { + *m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>'; + return true; + } + uint32_t num_children = *num_children_or_err; if (num_children) { m_stream->PutChar('('); bool did_print_children = false; for (uint32_t idx = 0; idx < num_children; ++idx) { - lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx)); + lldb::ValueObjectSP child_sp(synth_valobj.GetChildAtIndex(idx)); if (child_sp) child_sp = child_sp->GetQualifiedRepresentationIfAvailable( m_options.m_use_dynamic, m_options.m_use_synthetic); @@ -792,9 +823,13 @@ bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { return true; } -void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, - bool summary_printed) { - PrintObjectDescriptionIfNeeded(value_printed, summary_printed); +llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, + bool summary_printed) { + auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed); + if (error) + return error; + + ValueObject &valobj = GetMostSpecializedValue(); DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth; const bool print_children = ShouldPrintChildren(curr_ptr_depth); @@ -803,13 +838,13 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, !m_options.m_allow_oneliner_mode || m_options.m_flat_output || (m_options.m_pointer_as_array) || m_options.m_show_location) ? false - : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); + : DataVisualization::ShouldPrintAsOneLiner(valobj); if (print_children && IsInstancePointer()) { - uint64_t instance_ptr_value = m_valobj->GetValueAsUnsigned(0); + uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0); if (m_printed_instance_pointers->count(instance_ptr_value)) { // We already printed this instance-is-pointer thing, so don't expand it. m_stream->PutCString(" {...}\n"); - return; + return llvm::Error::success(); } else { // Remember this guy for future reference. m_printed_instance_pointers->emplace(instance_ptr_value); @@ -831,12 +866,13 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, // the user. The warning tells the user that the limit has been reached, but // more importantly tells them how to expand the limit if desired. if (m_options.m_max_depth_is_default) - m_valobj->GetTargetSP() + valobj.GetTargetSP() ->GetDebugger() .GetCommandInterpreter() .SetReachedMaximumDepth(); } else m_stream->EOL(); + return llvm::Error::success(); } bool ValueObjectPrinter::HasReachedMaximumDepth() { diff --git a/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp b/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp index 57dae0b2c71f..19de204c2435 100644 --- a/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp +++ b/contrib/llvm-project/lldb/source/DataFormatters/VectorType.cpp @@ -9,6 +9,7 @@ #include "lldb/DataFormatters/VectorType.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" @@ -224,10 +225,16 @@ public: ~VectorTypeSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override { return m_num_children; } + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_num_children; + } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { - if (idx >= CalculateNumChildren()) + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { + auto num_children_or_err = CalculateNumChildren(); + if (!num_children_or_err) + return ValueObjectConstResult::Create( + nullptr, Status(num_children_or_err.takeError())); + if (idx >= *num_children_or_err) return {}; std::optional<uint64_t> size = m_child_type.GetByteSize(nullptr); if (!size) @@ -245,7 +252,7 @@ public: return child_sp; } - bool Update() override { + lldb::ChildCacheState Update() override { m_parent_format = m_backend.GetFormat(); CompilerType parent_type(m_backend.GetCompilerType()); CompilerType element_type; @@ -258,7 +265,7 @@ public: ::CalculateNumChildren(element_type, num_elements, m_child_type) .value_or(0); m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type); - return false; + return lldb::ChildCacheState::eRefetch; } bool MightHaveChildren() override { return true; } @@ -266,7 +273,7 @@ public: size_t GetIndexOfChildWithName(ConstString name) override { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } @@ -293,7 +300,8 @@ bool lldb_private::formatters::VectorTypeSummaryProvider( s.PutChar('('); bool first = true; - size_t idx = 0, len = synthetic_children->CalculateNumChildren(); + size_t idx = 0, + len = synthetic_children->CalculateNumChildrenIgnoringErrors(); for (; idx < len; idx++) { auto child_sp = synthetic_children->GetChildAtIndex(idx); diff --git a/contrib/llvm-project/lldb/source/Expression/DWARFExpression.cpp b/contrib/llvm-project/lldb/source/Expression/DWARFExpression.cpp index fe4928d4f43a..444e44b39289 100644 --- a/contrib/llvm-project/lldb/source/Expression/DWARFExpression.cpp +++ b/contrib/llvm-project/lldb/source/Expression/DWARFExpression.cpp @@ -94,51 +94,38 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) { m_reg_kind = reg_kind; } - -static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx, - lldb::RegisterKind reg_kind, - uint32_t reg_num, Status *error_ptr, - Value &value) { - if (reg_ctx == nullptr) { - if (error_ptr) - error_ptr->SetErrorString("No register context in frame.\n"); - } else { - uint32_t native_reg = - reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); - if (native_reg == LLDB_INVALID_REGNUM) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("Unable to convert register " - "kind=%u reg_num=%u to a native " - "register number.\n", - reg_kind, reg_num); - } else { - const RegisterInfo *reg_info = - reg_ctx->GetRegisterInfoAtIndex(native_reg); - RegisterValue reg_value; - if (reg_ctx->ReadRegister(reg_info, reg_value)) { - if (reg_value.GetScalarValue(value.GetScalar())) { - value.SetValueType(Value::ValueType::Scalar); - value.SetContext(Value::ContextType::RegisterInfo, - const_cast<RegisterInfo *>(reg_info)); - if (error_ptr) - error_ptr->Clear(); - return true; - } else { - // If we get this error, then we need to implement a value buffer in - // the dwarf expression evaluation function... - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "register %s can't be converted to a scalar value", - reg_info->name); - } - } else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat("register %s is not available", - reg_info->name); - } +static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + uint32_t reg_num, Value &value) { + if (reg_ctx == nullptr) + return llvm::createStringError("no register context in frame"); + + const uint32_t native_reg = + reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); + if (native_reg == LLDB_INVALID_REGNUM) + return llvm::createStringError( + "unable to convert register kind=%u reg_num=%u to a native " + "register number", + reg_kind, reg_num); + + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(native_reg); + RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + if (reg_value.GetScalarValue(value.GetScalar())) { + value.SetValueType(Value::ValueType::Scalar); + value.SetContext(Value::ContextType::RegisterInfo, + const_cast<RegisterInfo *>(reg_info)); + return llvm::Error::success(); } + + // If we get this error, then we need to implement a value buffer in + // the dwarf expression evaluation function... + return llvm::createStringError( + "register %s can't be converted to a scalar value", reg_info->name); } - return false; + + return llvm::createStringError("register %s is not available", + reg_info->name); } /// Return the length in bytes of the set of operands for \p op. No guarantees @@ -541,12 +528,12 @@ bool DWARFExpression::LinkThreadLocalStorage( return true; } -static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, - ExecutionContext *exe_ctx, - RegisterContext *reg_ctx, - const DataExtractor &opcodes, - lldb::offset_t &opcode_offset, - Status *error_ptr, Log *log) { +static llvm::Error Evaluate_DW_OP_entry_value(std::vector<Value> &stack, + ExecutionContext *exe_ctx, + RegisterContext *reg_ctx, + const DataExtractor &opcodes, + lldb::offset_t &opcode_offset, + Log *log) { // DW_OP_entry_value(sub-expr) describes the location a variable had upon // function entry: this variable location is presumed to be optimized out at // the current PC value. The caller of the function may have call site @@ -593,26 +580,22 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, // 1. Find the function which pushed the current frame onto the stack. if ((!exe_ctx || !exe_ctx->HasTargetScope()) || !reg_ctx) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no exe/reg context"); - return false; + return llvm::createStringError("no exe/reg context"); } StackFrame *current_frame = exe_ctx->GetFramePtr(); Thread *thread = exe_ctx->GetThreadPtr(); - if (!current_frame || !thread) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no current frame/thread"); - return false; - } + if (!current_frame || !thread) + return llvm::createStringError("no current frame/thread"); Target &target = exe_ctx->GetTargetRef(); StackFrameSP parent_frame = nullptr; addr_t return_pc = LLDB_INVALID_ADDRESS; uint32_t current_frame_idx = current_frame->GetFrameIndex(); - uint32_t num_frames = thread->GetStackFrameCount(); - for (uint32_t parent_frame_idx = current_frame_idx + 1; - parent_frame_idx < num_frames; ++parent_frame_idx) { + + for (uint32_t parent_frame_idx = current_frame_idx + 1;;parent_frame_idx++) { parent_frame = thread->GetStackFrameAtIndex(parent_frame_idx); - // Require a valid sequence of frames. + // If this is null, we're at the end of the stack. if (!parent_frame) break; @@ -621,9 +604,7 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, // parent frame. if (return_pc == LLDB_INVALID_ADDRESS) { return_pc = parent_frame->GetFrameCodeAddress().GetLoadAddress(&target); - LLDB_LOG(log, - "Evaluate_DW_OP_entry_value: immediate ancestor with pc = {0:x}", - return_pc); + LLDB_LOG(log, "immediate ancestor with pc = {0:x}", return_pc); } // If we've found an inlined frame, skip it (these have no call site @@ -635,25 +616,20 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, break; } if (!parent_frame || !parent_frame->GetRegisterContext()) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no parent frame with reg ctx"); - return false; + return llvm::createStringError("no parent frame with reg ctx"); } Function *parent_func = parent_frame->GetSymbolContext(eSymbolContextFunction).function; - if (!parent_func) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no parent function"); - return false; - } + if (!parent_func) + return llvm::createStringError("no parent function"); // 2. Find the call edge in the parent function responsible for creating the // current activation. Function *current_func = current_frame->GetSymbolContext(eSymbolContextFunction).function; - if (!current_func) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no current function"); - return false; - } + if (!current_func) + return llvm::createStringError("no current function"); CallEdge *call_edge = nullptr; ModuleList &modlist = target.GetImages(); @@ -664,17 +640,14 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, // produced by an ambiguous tail call. In this case, refuse to proceed. call_edge = parent_func->GetCallEdgeForReturnAddress(return_pc, target); if (!call_edge) { - LLDB_LOG(log, - "Evaluate_DW_OP_entry_value: no call edge for retn-pc = {0:x} " - "in parent frame {1}", - return_pc, parent_func->GetName()); - return false; + return llvm::createStringError( + llvm::formatv("no call edge for retn-pc = {0:x} in parent frame {1}", + return_pc, parent_func->GetName())); } Function *callee_func = call_edge->GetCallee(modlist, parent_exe_ctx); if (callee_func != current_func) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: ambiguous call sequence, " - "can't find real parent frame"); - return false; + return llvm::createStringError( + "ambiguous call sequence, can't find real parent frame"); } } else { // The StackFrameList solver machinery has deduced that an unambiguous tail @@ -687,21 +660,17 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, } } } - if (!call_edge) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no unambiguous edge from parent " - "to current function"); - return false; - } + if (!call_edge) + return llvm::createStringError("no unambiguous edge from parent " + "to current function"); // 3. Attempt to locate the DW_OP_entry_value expression in the set of // available call site parameters. If found, evaluate the corresponding // parameter in the context of the parent frame. const uint32_t subexpr_len = opcodes.GetULEB128(&opcode_offset); const void *subexpr_data = opcodes.GetData(&opcode_offset, subexpr_len); - if (!subexpr_data) { - LLDB_LOG(log, "Evaluate_DW_OP_entry_value: subexpr could not be read"); - return false; - } + if (!subexpr_data) + return llvm::createStringError("subexpr could not be read"); const CallSiteParameter *matched_param = nullptr; for (const CallSiteParameter ¶m : call_edge->GetCallSiteParameters()) { @@ -727,28 +696,26 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack, break; } } - if (!matched_param) { - LLDB_LOG(log, - "Evaluate_DW_OP_entry_value: no matching call site param found"); - return false; - } + if (!matched_param) + return llvm::createStringError("no matching call site param found"); // TODO: Add support for DW_OP_push_object_address within a DW_OP_entry_value // subexpresion whenever llvm does. - Value result; const DWARFExpressionList ¶m_expr = matched_param->LocationInCaller; - if (!param_expr.Evaluate(&parent_exe_ctx, - parent_frame->GetRegisterContext().get(), - LLDB_INVALID_ADDRESS, - /*initial_value_ptr=*/nullptr, - /*object_address_ptr=*/nullptr, result, error_ptr)) { + + llvm::Expected<Value> maybe_result = param_expr.Evaluate( + &parent_exe_ctx, parent_frame->GetRegisterContext().get(), + LLDB_INVALID_ADDRESS, + /*initial_value_ptr=*/nullptr, + /*object_address_ptr=*/nullptr); + if (!maybe_result) { LLDB_LOG(log, "Evaluate_DW_OP_entry_value: call site param evaluation failed"); - return false; + return maybe_result.takeError(); } - stack.push_back(result); - return true; + stack.push_back(*maybe_result); + return llvm::Error::success(); } namespace { @@ -802,7 +769,6 @@ void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu, /// /// \param exe_ctx Pointer to the execution context /// \param module_sp shared_ptr contains the module if we have one -/// \param error_ptr pointer to Status object if we have one /// \param dw_op_type C-style string used to vary the error output /// \param file_addr the file address we are trying to resolve and turn into a /// load address @@ -813,32 +779,22 @@ void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu, /// the load address succeed or an empty Optinal otherwise. If /// check_sectionoffset is true we consider LLDB_INVALID_ADDRESS a /// success if so_addr.IsSectionOffset() is true. -static std::optional<lldb::addr_t> +static llvm::Expected<lldb::addr_t> ResolveLoadAddress(ExecutionContext *exe_ctx, lldb::ModuleSP &module_sp, - Status *error_ptr, const char *dw_op_type, - lldb::addr_t file_addr, Address &so_addr, - bool check_sectionoffset = false) { - if (!module_sp) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "need module to resolve file address for %s", dw_op_type); - return {}; - } + const char *dw_op_type, lldb::addr_t file_addr, + Address &so_addr, bool check_sectionoffset = false) { + if (!module_sp) + return llvm::createStringError("need module to resolve file address for %s", + dw_op_type); - if (!module_sp->ResolveFileAddress(file_addr, so_addr)) { - if (error_ptr) - error_ptr->SetErrorString("failed to resolve file address in module"); - return {}; - } + if (!module_sp->ResolveFileAddress(file_addr, so_addr)) + return llvm::createStringError("failed to resolve file address in module"); - addr_t load_addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); + const addr_t load_addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); if (load_addr == LLDB_INVALID_ADDRESS && - (check_sectionoffset && !so_addr.IsSectionOffset())) { - if (error_ptr) - error_ptr->SetErrorString("failed to resolve load address"); - return {}; - } + (check_sectionoffset && !so_addr.IsSectionOffset())) + return llvm::createStringError("failed to resolve load address"); return load_addr; } @@ -863,19 +819,15 @@ static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes, return addr_data.GetAddress(&addr_data_offset); } -bool DWARFExpression::Evaluate( +llvm::Expected<Value> DWARFExpression::Evaluate( ExecutionContext *exe_ctx, RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor &opcodes, const DWARFUnit *dwarf_cu, const lldb::RegisterKind reg_kind, - const Value *initial_value_ptr, const Value *object_address_ptr, - Value &result, Status *error_ptr) { + const Value *initial_value_ptr, const Value *object_address_ptr) { - if (opcodes.GetByteSize() == 0) { - if (error_ptr) - error_ptr->SetErrorString( - "no location, value may have been optimized out"); - return false; - } + if (opcodes.GetByteSize() == 0) + return llvm::createStringError( + "no location, value may have been optimized out"); std::vector<Value> stack; Process *process = nullptr; @@ -936,6 +888,14 @@ bool DWARFExpression::Evaluate( DW_OP_value_to_name(op)); } + if (std::optional<unsigned> arity = + llvm::dwarf::OperationArity(static_cast<LocationAtom>(op))) { + if (stack.size() < *arity) + return llvm::createStringError( + "%s needs at least %d stack entries (stack has %d entries)", + DW_OP_value_to_name(op), *arity, stack.size()); + } + switch (op) { // The DW_OP_addr operation has a single operand that encodes a machine // address and whose size is the size of an address on the target machine. @@ -995,11 +955,9 @@ bool DWARFExpression::Evaluate( // retrieved from the dereferenced address is the size of an address on the // target machine. case DW_OP_deref: { - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString("Expression stack empty for DW_OP_deref."); - return false; - } + if (stack.empty()) + return llvm::createStringError( + "expression stack empty for DW_OP_deref"); Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) { case Value::ValueType::HostAddress: { @@ -1015,10 +973,10 @@ bool DWARFExpression::Evaluate( Address so_addr; auto maybe_load_addr = ResolveLoadAddress( - exe_ctx, module_sp, error_ptr, "DW_OP_deref", file_addr, so_addr); + exe_ctx, module_sp, "DW_OP_deref", file_addr, so_addr); if (!maybe_load_addr) - return false; + return maybe_load_addr.takeError(); stack.back().GetScalar() = *maybe_load_addr; // Fall through to load address promotion code below. @@ -1042,30 +1000,22 @@ bool DWARFExpression::Evaluate( stack.back().GetScalar() = pointer_value; stack.back().ClearContext(); } else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "Failed to dereference pointer from 0x%" PRIx64 - " for DW_OP_deref: %s\n", - pointer_addr, error.AsCString()); - return false; + return llvm::createStringError( + "Failed to dereference pointer from 0x%" PRIx64 + " for DW_OP_deref: %s\n", + pointer_addr, error.AsCString()); } } else { - if (error_ptr) - error_ptr->SetErrorString("NULL process for DW_OP_deref.\n"); - return false; + return llvm::createStringError("NULL process for DW_OP_deref"); } } else { - if (error_ptr) - error_ptr->SetErrorString( - "NULL execution context for DW_OP_deref.\n"); - return false; + return llvm::createStringError( + "NULL execution context for DW_OP_deref"); } break; case Value::ValueType::Invalid: - if (error_ptr) - error_ptr->SetErrorString("Invalid value type for DW_OP_deref.\n"); - return false; + return llvm::createStringError("invalid value type for DW_OP_deref"); } } break; @@ -1084,18 +1034,13 @@ bool DWARFExpression::Evaluate( // expression stack. case DW_OP_deref_size: { if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack empty for DW_OP_deref_size."); - return false; + return llvm::createStringError( + "expression stack empty for DW_OP_deref_size"); } uint8_t size = opcodes.GetU8(&offset); if (size > 8) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "Invalid address size for DW_OP_deref_size: %d\n", - size); - return false; + return llvm::createStringError( + "Invalid address size for DW_OP_deref_size: %d\n", size); } Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) { @@ -1143,13 +1088,12 @@ bool DWARFExpression::Evaluate( auto file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); Address so_addr; - auto maybe_load_addr = - ResolveLoadAddress(exe_ctx, module_sp, error_ptr, - "DW_OP_deref_size", file_addr, so_addr, - /*check_sectionoffset=*/true); + auto maybe_load_addr = ResolveLoadAddress( + exe_ctx, module_sp, "DW_OP_deref_size", file_addr, so_addr, + /*check_sectionoffset=*/true); if (!maybe_load_addr) - return false; + return maybe_load_addr.takeError(); addr_t load_addr = *maybe_load_addr; @@ -1167,12 +1111,10 @@ bool DWARFExpression::Evaluate( stack.back().ClearContext(); break; } else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "Failed to dereference pointer for DW_OP_deref_size: " - "%s\n", - error.AsCString()); - return false; + return llvm::createStringError( + "Failed to dereference pointer for DW_OP_deref_size: " + "%s\n", + error.AsCString()); } } stack.back().GetScalar() = load_addr; @@ -1196,30 +1138,24 @@ bool DWARFExpression::Evaluate( process->GetByteOrder(), size); stack.back().ClearContext(); } else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "Failed to dereference pointer from 0x%" PRIx64 - " for DW_OP_deref: %s\n", - pointer_addr, error.AsCString()); - return false; + return llvm::createStringError( + "Failed to dereference pointer from 0x%" PRIx64 + " for DW_OP_deref: %s\n", + pointer_addr, error.AsCString()); } } else { - if (error_ptr) - error_ptr->SetErrorString("NULL process for DW_OP_deref_size.\n"); - return false; + + return llvm::createStringError("NULL process for DW_OP_deref_size"); } } else { - if (error_ptr) - error_ptr->SetErrorString( - "NULL execution context for DW_OP_deref_size.\n"); - return false; + return llvm::createStringError( + "NULL execution context for DW_OP_deref_size"); } break; case Value::ValueType::Invalid: - if (error_ptr) - error_ptr->SetErrorString("Invalid value for DW_OP_deref_size.\n"); - return false; + + return llvm::createStringError("invalid value for DW_OP_deref_size"); } } break; @@ -1240,9 +1176,7 @@ bool DWARFExpression::Evaluate( // extended to the size of an address on the target machine before being // pushed on the expression stack. case DW_OP_xderef_size: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size."); - return false; + return llvm::createStringError("unimplemented opcode: DW_OP_xderef_size"); // OPCODE: DW_OP_xderef // OPERANDS: none // DESCRIPTION: Provides an extended dereference mechanism. The entry at @@ -1254,9 +1188,7 @@ bool DWARFExpression::Evaluate( // retrieved from the dereferenced address is the size of an address on the // target machine. case DW_OP_xderef: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef."); - return false; + return llvm::createStringError("unimplemented opcode: DW_OP_xderef"); // All DW_OP_constXXX opcodes have a single operand as noted below: // @@ -1309,9 +1241,7 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: duplicates the value at the top of the stack case DW_OP_dup: if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString("Expression stack empty for DW_OP_dup."); - return false; + return llvm::createStringError("expression stack empty for DW_OP_dup"); } else stack.push_back(stack.back()); break; @@ -1321,9 +1251,7 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the value at the top of the stack case DW_OP_drop: if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString("Expression stack empty for DW_OP_drop."); - return false; + return llvm::createStringError("expression stack empty for DW_OP_drop"); } else stack.pop_back(); break; @@ -1333,13 +1261,7 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: Duplicates the entry currently second in the stack at // the top of the stack. case DW_OP_over: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_over."); - return false; - } else - stack.push_back(stack[stack.size() - 2]); + stack.push_back(stack[stack.size() - 2]); break; // OPCODE: DW_OP_pick @@ -1351,10 +1273,8 @@ bool DWARFExpression::Evaluate( if (pick_idx < stack.size()) stack.push_back(stack[stack.size() - 1 - pick_idx]); else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "Index %u out of range for DW_OP_pick.\n", pick_idx); - return false; + return llvm::createStringError( + "Index %u out of range for DW_OP_pick.\n", pick_idx); } } break; @@ -1364,16 +1284,9 @@ bool DWARFExpression::Evaluate( // of the stack becomes the second stack entry, and the second entry // becomes the top of the stack case DW_OP_swap: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_swap."); - return false; - } else { - tmp = stack.back(); - stack.back() = stack[stack.size() - 2]; - stack[stack.size() - 2] = tmp; - } + tmp = stack.back(); + stack.back() = stack[stack.size() - 2]; + stack[stack.size() - 2] = tmp; break; // OPCODE: DW_OP_rot @@ -1382,20 +1295,13 @@ bool DWARFExpression::Evaluate( // the top of the stack becomes the third stack entry, the second entry // becomes the top of the stack, and the third entry becomes the second // entry. - case DW_OP_rot: - if (stack.size() < 3) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 3 items for DW_OP_rot."); - return false; - } else { - size_t last_idx = stack.size() - 1; - Value old_top = stack[last_idx]; - stack[last_idx] = stack[last_idx - 1]; - stack[last_idx - 1] = stack[last_idx - 2]; - stack[last_idx - 2] = old_top; - } - break; + case DW_OP_rot: { + size_t last_idx = stack.size() - 1; + Value old_top = stack[last_idx]; + stack[last_idx] = stack[last_idx - 1]; + stack[last_idx - 1] = stack[last_idx - 2]; + stack[last_idx - 2] = old_top; + } break; // OPCODE: DW_OP_abs // OPERANDS: none @@ -1403,16 +1309,9 @@ bool DWARFExpression::Evaluate( // value and pushes its absolute value. If the absolute value can not be // represented, the result is undefined. case DW_OP_abs: - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_abs."); - return false; - } else if (!stack.back().ResolveValue(exe_ctx).AbsoluteValue()) { - if (error_ptr) - error_ptr->SetErrorString( - "Failed to take the absolute value of the first stack item."); - return false; + if (!stack.back().ResolveValue(exe_ctx).AbsoluteValue()) { + return llvm::createStringError( + "failed to take the absolute value of the first stack item"); } break; @@ -1421,17 +1320,10 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack values, performs a bitwise and // operation on the two, and pushes the result. case DW_OP_and: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_and."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_div @@ -1439,51 +1331,32 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack values, divides the former second // entry by the former top of the stack using signed division, and pushes // the result. - case DW_OP_div: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_div."); - return false; - } else { - tmp = stack.back(); - if (tmp.ResolveValue(exe_ctx).IsZero()) { - if (error_ptr) - error_ptr->SetErrorString("Divide by zero."); - return false; - } else { - stack.pop_back(); - Scalar divisor, dividend; - divisor = tmp.ResolveValue(exe_ctx); - dividend = stack.back().ResolveValue(exe_ctx); - divisor.MakeSigned(); - dividend.MakeSigned(); - stack.back() = dividend / divisor; - if (!stack.back().ResolveValue(exe_ctx).IsValid()) { - if (error_ptr) - error_ptr->SetErrorString("Divide failed."); - return false; - } - } - } - break; + case DW_OP_div: { + tmp = stack.back(); + if (tmp.ResolveValue(exe_ctx).IsZero()) + return llvm::createStringError("divide by zero"); + + stack.pop_back(); + Scalar divisor, dividend; + divisor = tmp.ResolveValue(exe_ctx); + dividend = stack.back().ResolveValue(exe_ctx); + divisor.MakeSigned(); + dividend.MakeSigned(); + stack.back() = dividend / divisor; + + if (!stack.back().ResolveValue(exe_ctx).IsValid()) + return llvm::createStringError("divide failed"); + } break; // OPCODE: DW_OP_minus // OPERANDS: none // DESCRIPTION: pops the top two stack values, subtracts the former top // of the stack from the former second entry, and pushes the result. case DW_OP_minus: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_minus."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_mod @@ -1492,17 +1365,10 @@ bool DWARFExpression::Evaluate( // the calculation: former second stack entry modulo the former top of the // stack. case DW_OP_mod: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_mod."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_mul @@ -1510,35 +1376,18 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack entries, multiplies them // together, and pushes the result. case DW_OP_mul: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_mul."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_neg // OPERANDS: none // DESCRIPTION: pops the top stack entry, and pushes its negation. case DW_OP_neg: - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_neg."); - return false; - } else { - if (!stack.back().ResolveValue(exe_ctx).UnaryNegate()) { - if (error_ptr) - error_ptr->SetErrorString("Unary negate failed."); - return false; - } - } + if (!stack.back().ResolveValue(exe_ctx).UnaryNegate()) + return llvm::createStringError("unary negate failed"); break; // OPCODE: DW_OP_not @@ -1546,18 +1395,8 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top stack entry, and pushes its bitwise // complement case DW_OP_not: - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_not."); - return false; - } else { - if (!stack.back().ResolveValue(exe_ctx).OnesComplement()) { - if (error_ptr) - error_ptr->SetErrorString("Logical NOT failed."); - return false; - } - } + if (!stack.back().ResolveValue(exe_ctx).OnesComplement()) + return llvm::createStringError("logical NOT failed"); break; // OPCODE: DW_OP_or @@ -1565,17 +1404,10 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack entries, performs a bitwise or // operation on the two, and pushes the result. case DW_OP_or: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_or."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_plus @@ -1583,39 +1415,22 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack entries, adds them together, and // pushes the result. case DW_OP_plus: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_plus."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().GetScalar() += tmp.GetScalar(); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().GetScalar() += tmp.GetScalar(); break; // OPCODE: DW_OP_plus_uconst // OPERANDS: none // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128 // constant operand and pushes the result. - case DW_OP_plus_uconst: - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_plus_uconst."); - return false; - } else { - const uint64_t uconst_value = opcodes.GetULEB128(&offset); - // Implicit conversion from a UINT to a Scalar... - stack.back().GetScalar() += uconst_value; - if (!stack.back().GetScalar().IsValid()) { - if (error_ptr) - error_ptr->SetErrorString("DW_OP_plus_uconst failed."); - return false; - } - } - break; + case DW_OP_plus_uconst: { + const uint64_t uconst_value = opcodes.GetULEB128(&offset); + // Implicit conversion from a UINT to a Scalar... + stack.back().GetScalar() += uconst_value; + if (!stack.back().GetScalar().IsValid()) + return llvm::createStringError("DW_OP_plus_uconst failed"); + } break; // OPCODE: DW_OP_shl // OPERANDS: none @@ -1623,16 +1438,9 @@ bool DWARFExpression::Evaluate( // second entry left by the number of bits specified by the former top of // the stack, and pushes the result. case DW_OP_shl: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_shl."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_shr @@ -1641,21 +1449,11 @@ bool DWARFExpression::Evaluate( // entry right logically (filling with zero bits) by the number of bits // specified by the former top of the stack, and pushes the result. case DW_OP_shr: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_shr."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - if (!stack.back().ResolveValue(exe_ctx).ShiftRightLogical( - tmp.ResolveValue(exe_ctx))) { - if (error_ptr) - error_ptr->SetErrorString("DW_OP_shr failed."); - return false; - } - } + tmp = stack.back(); + stack.pop_back(); + if (!stack.back().ResolveValue(exe_ctx).ShiftRightLogical( + tmp.ResolveValue(exe_ctx))) + return llvm::createStringError("DW_OP_shr failed"); break; // OPCODE: DW_OP_shra @@ -1665,16 +1463,9 @@ bool DWARFExpression::Evaluate( // sign for the result) by the number of bits specified by the former top // of the stack, and pushes the result. case DW_OP_shra: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_shra."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_xor @@ -1682,17 +1473,10 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: pops the top two stack entries, performs the bitwise // exclusive-or operation on the two, and pushes the result. case DW_OP_xor: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_xor."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_skip @@ -1710,11 +1494,9 @@ bool DWARFExpression::Evaluate( if (new_offset <= opcodes.GetByteSize()) offset = new_offset; else { - if (error_ptr) - error_ptr->SetErrorStringWithFormatv( - "Invalid opcode offset in DW_OP_skip: {0}+({1}) > {2}", offset, - skip_offset, opcodes.GetByteSize()); - return false; + return llvm::createStringError(llvm::formatv( + "Invalid opcode offset in DW_OP_skip: {0}+({1}) > {2}", offset, + skip_offset, opcodes.GetByteSize())); } } break; @@ -1725,34 +1507,25 @@ bool DWARFExpression::Evaluate( // value popped is not the constant 0, the 2-byte constant operand is the // number of bytes of the DWARF expression to skip forward or backward from // the current operation, beginning after the 2-byte constant. - case DW_OP_bra: - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_bra."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - int16_t bra_offset = (int16_t)opcodes.GetU16(&offset); - Scalar zero(0); - if (tmp.ResolveValue(exe_ctx) != zero) { - lldb::offset_t new_offset = offset + bra_offset; - // New offset can point at the end of the data, in this case we should - // terminate the DWARF expression evaluation (will happen in the loop - // condition). - if (new_offset <= opcodes.GetByteSize()) - offset = new_offset; - else { - if (error_ptr) - error_ptr->SetErrorStringWithFormatv( - "Invalid opcode offset in DW_OP_bra: {0}+({1}) > {2}", offset, - bra_offset, opcodes.GetByteSize()); - return false; - } + case DW_OP_bra: { + tmp = stack.back(); + stack.pop_back(); + int16_t bra_offset = (int16_t)opcodes.GetU16(&offset); + Scalar zero(0); + if (tmp.ResolveValue(exe_ctx) != zero) { + lldb::offset_t new_offset = offset + bra_offset; + // New offset can point at the end of the data, in this case we should + // terminate the DWARF expression evaluation (will happen in the loop + // condition). + if (new_offset <= opcodes.GetByteSize()) + offset = new_offset; + else { + return llvm::createStringError(llvm::formatv( + "Invalid opcode offset in DW_OP_bra: {0}+({1}) > {2}", offset, + bra_offset, opcodes.GetByteSize())); } } - break; + } break; // OPCODE: DW_OP_eq // OPERANDS: none @@ -1762,17 +1535,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_eq: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_eq."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_ge @@ -1783,17 +1549,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_ge: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_ge."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_gt @@ -1804,17 +1563,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_gt: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_gt."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_le @@ -1825,17 +1577,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_le: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_le."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_lt @@ -1846,17 +1591,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_lt: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_lt."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_ne @@ -1867,17 +1605,10 @@ bool DWARFExpression::Evaluate( // of the operation is true or the constant value 0 if the result of the // operation is false. case DW_OP_ne: - if (stack.size() < 2) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 2 items for DW_OP_ne."); - return false; - } else { - tmp = stack.back(); - stack.pop_back(); - stack.back().ResolveValue(exe_ctx) = - stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx); - } + tmp = stack.back(); + stack.pop_back(); + stack.back().ResolveValue(exe_ctx) = + stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx); break; // OPCODE: DW_OP_litn @@ -1958,10 +1689,10 @@ bool DWARFExpression::Evaluate( dwarf4_location_description_kind = Register; reg_num = op - DW_OP_reg0; - if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp)) - stack.push_back(tmp); - else - return false; + if (llvm::Error err = + ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, tmp)) + return err; + stack.push_back(tmp); } break; // OPCODE: DW_OP_regx // OPERANDS: @@ -1970,10 +1701,11 @@ bool DWARFExpression::Evaluate( case DW_OP_regx: { dwarf4_location_description_kind = Register; reg_num = opcodes.GetULEB128(&offset); - if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp)) - stack.push_back(tmp); - else - return false; + Status read_err; + if (llvm::Error err = + ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, tmp)) + return err; + stack.push_back(tmp); } break; // OPCODE: DW_OP_bregN @@ -2014,16 +1746,15 @@ bool DWARFExpression::Evaluate( case DW_OP_breg30: case DW_OP_breg31: { reg_num = op - DW_OP_breg0; - - if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, - tmp)) { - int64_t breg_offset = opcodes.GetSLEB128(&offset); - tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; - tmp.ClearContext(); - stack.push_back(tmp); - stack.back().SetValueType(Value::ValueType::LoadAddress); - } else - return false; + if (llvm::Error err = + ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, tmp)) + return err; + + int64_t breg_offset = opcodes.GetSLEB128(&offset); + tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; + tmp.ClearContext(); + stack.push_back(tmp); + stack.back().SetValueType(Value::ValueType::LoadAddress); } break; // OPCODE: DW_OP_bregx // OPERANDS: 2 @@ -2033,40 +1764,36 @@ bool DWARFExpression::Evaluate( // N plus an offset. case DW_OP_bregx: { reg_num = opcodes.GetULEB128(&offset); - - if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, - tmp)) { - int64_t breg_offset = opcodes.GetSLEB128(&offset); - tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; - tmp.ClearContext(); - stack.push_back(tmp); - stack.back().SetValueType(Value::ValueType::LoadAddress); - } else - return false; + if (llvm::Error err = + ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, tmp)) + return err; + + int64_t breg_offset = opcodes.GetSLEB128(&offset); + tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; + tmp.ClearContext(); + stack.push_back(tmp); + stack.back().SetValueType(Value::ValueType::LoadAddress); } break; case DW_OP_fbreg: if (exe_ctx) { if (frame) { Scalar value; - if (frame->GetFrameBaseValue(value, error_ptr)) { + Status fb_err; + if (frame->GetFrameBaseValue(value, &fb_err)) { int64_t fbreg_offset = opcodes.GetSLEB128(&offset); value += fbreg_offset; stack.push_back(value); stack.back().SetValueType(Value::ValueType::LoadAddress); } else - return false; + return fb_err.ToError(); } else { - if (error_ptr) - error_ptr->SetErrorString( - "Invalid stack frame in context for DW_OP_fbreg opcode."); - return false; + return llvm::createStringError( + "invalid stack frame in context for DW_OP_fbreg opcode"); } } else { - if (error_ptr) - error_ptr->SetErrorString( - "NULL execution context for DW_OP_fbreg.\n"); - return false; + return llvm::createStringError( + "NULL execution context for DW_OP_fbreg"); } break; @@ -2124,66 +1851,53 @@ bool DWARFExpression::Evaluate( const Value::ValueType curr_piece_source_value_type = curr_piece_source_value.GetValueType(); + Scalar &scalar = curr_piece_source_value.GetScalar(); + const lldb::addr_t addr = scalar.ULongLong(LLDB_INVALID_ADDRESS); switch (curr_piece_source_value_type) { case Value::ValueType::Invalid: - return false; + return llvm::createStringError("invalid value type"); case Value::ValueType::LoadAddress: - if (process) { + case Value::ValueType::FileAddress: { + if (target) { if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) { - lldb::addr_t load_addr = - curr_piece_source_value.GetScalar().ULongLong( - LLDB_INVALID_ADDRESS); - if (process->ReadMemory( - load_addr, curr_piece.GetBuffer().GetBytes(), - piece_byte_size, error) != piece_byte_size) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "failed to read memory DW_OP_piece(%" PRIu64 - ") from 0x%" PRIx64, - piece_byte_size, load_addr); - return false; + if (target->ReadMemory(addr, curr_piece.GetBuffer().GetBytes(), + piece_byte_size, error, + /*force_live_memory=*/false) != + piece_byte_size) { + const char *addr_type = (curr_piece_source_value_type == + Value::ValueType::LoadAddress) + ? "load" + : "file"; + return llvm::createStringError( + "failed to read memory DW_OP_piece(%" PRIu64 + ") from %s address 0x%" PRIx64, + piece_byte_size, addr_type, addr); } } else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "failed to resize the piece memory buffer for " - "DW_OP_piece(%" PRIu64 ")", - piece_byte_size); - return false; + return llvm::createStringError( + "failed to resize the piece memory buffer for " + "DW_OP_piece(%" PRIu64 ")", + piece_byte_size); } } - break; - - case Value::ValueType::FileAddress: - case Value::ValueType::HostAddress: - if (error_ptr) { - lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong( - LLDB_INVALID_ADDRESS); - error_ptr->SetErrorStringWithFormat( - "failed to read memory DW_OP_piece(%" PRIu64 - ") from %s address 0x%" PRIx64, - piece_byte_size, curr_piece_source_value.GetValueType() == - Value::ValueType::FileAddress - ? "file" - : "host", - addr); - } - return false; + } break; + case Value::ValueType::HostAddress: { + return llvm::createStringError( + "failed to read memory DW_OP_piece(%" PRIu64 + ") from host address 0x%" PRIx64, + piece_byte_size, addr); + } break; case Value::ValueType::Scalar: { uint32_t bit_size = piece_byte_size * 8; uint32_t bit_offset = 0; - Scalar &scalar = curr_piece_source_value.GetScalar(); if (!scalar.ExtractBitfield( bit_size, bit_offset)) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "unable to extract %" PRIu64 " bytes from a %" PRIu64 - " byte scalar value.", - piece_byte_size, - (uint64_t)curr_piece_source_value.GetScalar() - .GetByteSize()); - return false; + return llvm::createStringError( + "unable to extract %" PRIu64 " bytes from a %" PRIu64 + " byte scalar value.", + piece_byte_size, + (uint64_t)curr_piece_source_value.GetScalar().GetByteSize()); } // Create curr_piece with bit_size. By default Scalar // grows to the nearest host integer type. @@ -2202,27 +1916,20 @@ bool DWARFExpression::Evaluate( // so subsequent pieces will be able to access this piece and add // to it. if (pieces.AppendDataToHostBuffer(curr_piece) == 0) { - if (error_ptr) - error_ptr->SetErrorString("failed to append piece data"); - return false; + return llvm::createStringError("failed to append piece data"); } } else { // If this is the second or later piece there should be a value on // the stack. if (pieces.GetBuffer().GetByteSize() != op_piece_offset) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "DW_OP_piece for offset %" PRIu64 - " but top of stack is of size %" PRIu64, - op_piece_offset, pieces.GetBuffer().GetByteSize()); - return false; + return llvm::createStringError( + "DW_OP_piece for offset %" PRIu64 + " but top of stack is of size %" PRIu64, + op_piece_offset, pieces.GetBuffer().GetByteSize()); } - if (pieces.AppendDataToHostBuffer(curr_piece) == 0) { - if (error_ptr) - error_ptr->SetErrorString("failed to append piece data"); - return false; - } + if (pieces.AppendDataToHostBuffer(curr_piece) == 0) + return llvm::createStringError("failed to append piece data"); } } op_piece_offset += piece_byte_size; @@ -2235,10 +1942,8 @@ bool DWARFExpression::Evaluate( LocationDescriptionKind::Empty); // Reset for the next piece. dwarf4_location_description_kind = Memory; - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_bit_piece."); - return false; + return llvm::createStringError( + "expression stack needs at least 1 item for DW_OP_bit_piece"); } else { UpdateValueTypeFromLocationDescription( log, dwarf_cu, dwarf4_location_description_kind, &stack.back()); @@ -2248,30 +1953,26 @@ bool DWARFExpression::Evaluate( const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset); switch (stack.back().GetValueType()) { case Value::ValueType::Invalid: - return false; + return llvm::createStringError( + "unable to extract bit value from invalid value"); case Value::ValueType::Scalar: { if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size, piece_bit_offset)) { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "unable to extract %" PRIu64 " bit value with %" PRIu64 - " bit offset from a %" PRIu64 " bit scalar value.", - piece_bit_size, piece_bit_offset, - (uint64_t)(stack.back().GetScalar().GetByteSize() * 8)); - return false; + return llvm::createStringError( + "unable to extract %" PRIu64 " bit value with %" PRIu64 + " bit offset from a %" PRIu64 " bit scalar value.", + piece_bit_size, piece_bit_offset, + (uint64_t)(stack.back().GetScalar().GetByteSize() * 8)); } } break; case Value::ValueType::FileAddress: case Value::ValueType::LoadAddress: case Value::ValueType::HostAddress: - if (error_ptr) { - error_ptr->SetErrorStringWithFormat( - "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 - ", bit_offset = %" PRIu64 ") from an address value.", - piece_bit_size, piece_bit_offset); - } - return false; + return llvm::createStringError( + "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 + ", bit_offset = %" PRIu64 ") from an address value.", + piece_bit_size, piece_bit_offset); } } break; @@ -2291,9 +1992,8 @@ bool DWARFExpression::Evaluate( if (!data) { LLDB_LOG(log, "Evaluate_DW_OP_implicit_value: could not be read data"); - LLDB_ERRORF(error_ptr, "Could not evaluate %s.", - DW_OP_value_to_name(op)); - return false; + return llvm::createStringError("could not evaluate %s", + DW_OP_value_to_name(op)); } Value result(data, len); @@ -2303,8 +2003,8 @@ bool DWARFExpression::Evaluate( case DW_OP_implicit_pointer: { dwarf4_location_description_kind = Implicit; - LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op)); - return false; + return llvm::createStringError("Could not evaluate %s.", + DW_OP_value_to_name(op)); } // OPCODE: DW_OP_push_object_address @@ -2319,10 +2019,8 @@ bool DWARFExpression::Evaluate( if (object_address_ptr) stack.push_back(*object_address_ptr); else { - if (error_ptr) - error_ptr->SetErrorString("DW_OP_push_object_address used without " - "specifying an object address"); - return false; + return llvm::createStringError("DW_OP_push_object_address used without " + "specifying an object address"); } break; @@ -2345,9 +2043,7 @@ bool DWARFExpression::Evaluate( // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. case DW_OP_call2: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode DW_OP_call2."); - return false; + return llvm::createStringError("unimplemented opcode DW_OP_call2"); // OPCODE: DW_OP_call4 // OPERANDS: 1 // uint32_t compile unit relative offset of a DIE @@ -2368,9 +2064,7 @@ bool DWARFExpression::Evaluate( // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. case DW_OP_call4: - if (error_ptr) - error_ptr->SetErrorString("Unimplemented opcode DW_OP_call4."); - return false; + return llvm::createStringError("unimplemented opcode DW_OP_call4"); // OPCODE: DW_OP_stack_value // OPERANDS: None @@ -2379,12 +2073,6 @@ bool DWARFExpression::Evaluate( // value to be used. This is the actual object value and not the location. case DW_OP_stack_value: dwarf4_location_description_kind = Implicit; - if (stack.empty()) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_stack_value."); - return false; - } stack.back().SetValueType(Value::ValueType::Scalar); break; @@ -2396,12 +2084,6 @@ bool DWARFExpression::Evaluate( // DESCRIPTION: Pop the top stack element, convert it to a // different type, and push the result. case DW_OP_convert: { - if (stack.size() < 1) { - if (error_ptr) - error_ptr->SetErrorString( - "Expression stack needs at least 1 item for DW_OP_convert."); - return false; - } const uint64_t die_offset = opcodes.GetULEB128(&offset); uint64_t bit_size; bool sign; @@ -2409,39 +2091,29 @@ bool DWARFExpression::Evaluate( // The generic type has the size of an address on the target // machine and an unspecified signedness. Scalar has no // "unspecified signedness", so we use unsigned types. - if (!module_sp) { - if (error_ptr) - error_ptr->SetErrorString("No module"); - return false; - } + if (!module_sp) + return llvm::createStringError("no module"); sign = false; bit_size = module_sp->GetArchitecture().GetAddressByteSize() * 8; - if (!bit_size) { - if (error_ptr) - error_ptr->SetErrorString("unspecified architecture"); - return false; - } + if (!bit_size) + return llvm::createStringError("unspecified architecture"); } else { // Retrieve the type DIE that the value is being converted to. This // offset is compile unit relative so we need to fix it up. const uint64_t abs_die_offset = die_offset + dwarf_cu->GetOffset(); // FIXME: the constness has annoying ripple effects. DWARFDIE die = const_cast<DWARFUnit *>(dwarf_cu)->GetDIE(abs_die_offset); - if (!die) { - if (error_ptr) - error_ptr->SetErrorString("Cannot resolve DW_OP_convert type DIE"); - return false; - } + if (!die) + return llvm::createStringError( + "cannot resolve DW_OP_convert type DIE"); uint64_t encoding = die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user); bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; if (!bit_size) bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0); - if (!bit_size) { - if (error_ptr) - error_ptr->SetErrorString("Unsupported type size in DW_OP_convert"); - return false; - } + if (!bit_size) + return llvm::createStringError( + "unsupported type size in DW_OP_convert"); switch (encoding) { case DW_ATE_signed: case DW_ATE_signed_char: @@ -2452,9 +2124,8 @@ bool DWARFExpression::Evaluate( sign = false; break; default: - if (error_ptr) - error_ptr->SetErrorString("Unsupported encoding in DW_OP_convert"); - return false; + return llvm::createStringError( + "unsupported encoding in DW_OP_convert"); } } Scalar &top = stack.back().ResolveValue(exe_ctx); @@ -2476,15 +2147,15 @@ bool DWARFExpression::Evaluate( if (cfa != LLDB_INVALID_ADDRESS) { stack.push_back(Scalar(cfa)); stack.back().SetValueType(Value::ValueType::LoadAddress); - } else if (error_ptr) - error_ptr->SetErrorString("Stack frame does not include a canonical " - "frame address for DW_OP_call_frame_cfa " - "opcode."); + } else { + return llvm::createStringError( + "stack frame does not include a canonical " + "frame address for DW_OP_call_frame_cfa " + "opcode"); + } } else { - if (error_ptr) - error_ptr->SetErrorString("Invalid stack frame in context for " - "DW_OP_call_frame_cfa opcode."); - return false; + return llvm::createStringError("unvalid stack frame in context for " + "DW_OP_call_frame_cfa opcode"); } break; @@ -2497,29 +2168,20 @@ bool DWARFExpression::Evaluate( case DW_OP_form_tls_address: case DW_OP_GNU_push_tls_address: { if (stack.size() < 1) { - if (error_ptr) { - if (op == DW_OP_form_tls_address) - error_ptr->SetErrorString( - "DW_OP_form_tls_address needs an argument."); - else - error_ptr->SetErrorString( - "DW_OP_GNU_push_tls_address needs an argument."); - } - return false; + if (op == DW_OP_form_tls_address) + return llvm::createStringError( + "DW_OP_form_tls_address needs an argument"); + else + return llvm::createStringError( + "DW_OP_GNU_push_tls_address needs an argument"); } - if (!exe_ctx || !module_sp) { - if (error_ptr) - error_ptr->SetErrorString("No context to evaluate TLS within."); - return false; - } + if (!exe_ctx || !module_sp) + return llvm::createStringError("no context to evaluate TLS within"); Thread *thread = exe_ctx->GetThreadPtr(); - if (!thread) { - if (error_ptr) - error_ptr->SetErrorString("No thread to evaluate TLS within."); - return false; - } + if (!thread) + return llvm::createStringError("no thread to evaluate TLS within"); // Lookup the TLS block address for this thread and module. const addr_t tls_file_addr = @@ -2527,12 +2189,9 @@ bool DWARFExpression::Evaluate( const addr_t tls_load_addr = thread->GetThreadLocalData(module_sp, tls_file_addr); - if (tls_load_addr == LLDB_INVALID_ADDRESS) { - if (error_ptr) - error_ptr->SetErrorString( - "No TLS data currently exists for this thread."); - return false; - } + if (tls_load_addr == LLDB_INVALID_ADDRESS) + return llvm::createStringError( + "no TLS data currently exists for this thread"); stack.back().GetScalar() = tls_load_addr; stack.back().SetValueType(Value::ValueType::LoadAddress); @@ -2546,12 +2205,9 @@ bool DWARFExpression::Evaluate( // and the 0 based index is the ULEB128 encoded index. case DW_OP_addrx: case DW_OP_GNU_addr_index: { - if (!dwarf_cu) { - if (error_ptr) - error_ptr->SetErrorString("DW_OP_GNU_addr_index found without a " - "compile unit being specified"); - return false; - } + if (!dwarf_cu) + return llvm::createStringError("DW_OP_GNU_addr_index found without a " + "compile unit being specified"); uint64_t index = opcodes.GetULEB128(&offset); lldb::addr_t value = dwarf_cu->ReadAddressFromDebugAddrSection(index); stack.push_back(Scalar(value)); @@ -2574,10 +2230,8 @@ bool DWARFExpression::Evaluate( // encoded index. case DW_OP_GNU_const_index: { if (!dwarf_cu) { - if (error_ptr) - error_ptr->SetErrorString("DW_OP_GNU_const_index found without a " - "compile unit being specified"); - return false; + return llvm::createStringError("DW_OP_GNU_const_index found without a " + "compile unit being specified"); } uint64_t index = opcodes.GetULEB128(&offset); lldb::addr_t value = dwarf_cu->ReadAddressFromDebugAddrSection(index); @@ -2586,12 +2240,11 @@ bool DWARFExpression::Evaluate( case DW_OP_GNU_entry_value: case DW_OP_entry_value: { - if (!Evaluate_DW_OP_entry_value(stack, exe_ctx, reg_ctx, opcodes, offset, - error_ptr, log)) { - LLDB_ERRORF(error_ptr, "Could not evaluate %s.", - DW_OP_value_to_name(op)); - return false; - } + if (llvm::Error err = Evaluate_DW_OP_entry_value(stack, exe_ctx, reg_ctx, + opcodes, offset, log)) + return llvm::createStringError( + "could not evaluate DW_OP_entry_value: %s", + llvm::toString(std::move(err)).c_str()); break; } @@ -2602,23 +2255,18 @@ bool DWARFExpression::Evaluate( break; } } - if (error_ptr) - error_ptr->SetErrorStringWithFormatv( - "Unhandled opcode {0} in DWARFExpression", LocationAtom(op)); - return false; + return llvm::createStringError(llvm::formatv( + "Unhandled opcode {0} in DWARFExpression", LocationAtom(op))); } } if (stack.empty()) { // Nothing on the stack, check if we created a piece value from DW_OP_piece // or DW_OP_bit_piece opcodes - if (pieces.GetBuffer().GetByteSize()) { - result = pieces; - return true; - } - if (error_ptr) - error_ptr->SetErrorString("Stack empty after evaluation."); - return false; + if (pieces.GetBuffer().GetByteSize()) + return pieces; + + return llvm::createStringError("stack empty after evaluation"); } UpdateValueTypeFromLocationDescription( @@ -2635,8 +2283,7 @@ bool DWARFExpression::Evaluate( LLDB_LOGF(log, " %s", new_value.GetData()); } } - result = stack.back(); - return true; // Return true on success + return stack.back(); } bool DWARFExpression::ParseDWARFLocationList( diff --git a/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp b/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp index cba4e4e5858a..7a5cf9f9a0be 100644 --- a/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp +++ b/contrib/llvm-project/lldb/source/Expression/DWARFExpressionList.cpp @@ -198,12 +198,10 @@ void DWARFExpressionList::GetDescription(Stream *s, } } -bool DWARFExpressionList::Evaluate(ExecutionContext *exe_ctx, - RegisterContext *reg_ctx, - lldb::addr_t func_load_addr, - const Value *initial_value_ptr, - const Value *object_address_ptr, - Value &result, Status *error_ptr) const { +llvm::Expected<Value> DWARFExpressionList::Evaluate( + ExecutionContext *exe_ctx, RegisterContext *reg_ctx, + lldb::addr_t func_load_addr, const Value *initial_value_ptr, + const Value *object_address_ptr) const { ModuleSP module_sp = m_module_wp.lock(); DataExtractor data; RegisterKind reg_kind; @@ -217,32 +215,26 @@ bool DWARFExpressionList::Evaluate(ExecutionContext *exe_ctx, if (exe_ctx) frame = exe_ctx->GetFramePtr(); if (!frame) - return false; + return llvm::createStringError("no frame"); RegisterContextSP reg_ctx_sp = frame->GetRegisterContext(); if (!reg_ctx_sp) - return false; + return llvm::createStringError("no register context"); reg_ctx_sp->GetPCForSymbolication(pc); } if (!pc.IsValid()) { - if (error_ptr) - error_ptr->SetErrorString("Invalid PC in frame."); - return false; + return llvm::createStringError("Invalid PC in frame."); } addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr()); const DWARFExpression *entry = GetExpressionAtAddress(func_load_addr, pc_load_addr); - if (!entry) { - if (error_ptr) { - error_ptr->SetErrorString("variable not available"); - } - return false; - } + if (!entry) + return llvm::createStringError("variable not available"); expr = *entry; } expr.GetExpressionData(data); reg_kind = expr.GetRegisterKind(); return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data, m_dwarf_cu, reg_kind, initial_value_ptr, - object_address_ptr, result, error_ptr); + object_address_ptr); } diff --git a/contrib/llvm-project/lldb/source/Expression/DiagnosticManager.cpp b/contrib/llvm-project/lldb/source/Expression/DiagnosticManager.cpp index 9a1100df78db..a8330138f3d5 100644 --- a/contrib/llvm-project/lldb/source/Expression/DiagnosticManager.cpp +++ b/contrib/llvm-project/lldb/source/Expression/DiagnosticManager.cpp @@ -31,17 +31,17 @@ void DiagnosticManager::Dump(Log *log) { log->PutCString(str.c_str()); } -static const char *StringForSeverity(DiagnosticSeverity severity) { +static const char *StringForSeverity(lldb::Severity severity) { switch (severity) { // this should be exhaustive - case lldb_private::eDiagnosticSeverityError: + case lldb::eSeverityError: return "error: "; - case lldb_private::eDiagnosticSeverityWarning: + case lldb::eSeverityWarning: return "warning: "; - case lldb_private::eDiagnosticSeverityRemark: + case lldb::eSeverityInfo: return ""; } - llvm_unreachable("switch needs another case for DiagnosticSeverity enum"); + llvm_unreachable("switch needs another case for lldb::Severity enum"); } std::string DiagnosticManager::GetString(char separator) { @@ -65,8 +65,8 @@ std::string DiagnosticManager::GetString(char separator) { return ret; } -size_t DiagnosticManager::Printf(DiagnosticSeverity severity, - const char *format, ...) { +size_t DiagnosticManager::Printf(lldb::Severity severity, const char *format, + ...) { StreamString ss; va_list args; @@ -79,7 +79,7 @@ size_t DiagnosticManager::Printf(DiagnosticSeverity severity, return result; } -void DiagnosticManager::PutString(DiagnosticSeverity severity, +void DiagnosticManager::PutString(lldb::Severity severity, llvm::StringRef str) { if (str.empty()) return; diff --git a/contrib/llvm-project/lldb/source/Expression/ExpressionParser.cpp b/contrib/llvm-project/lldb/source/Expression/ExpressionParser.cpp new file mode 100644 index 000000000000..e9f7121c2499 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Expression/ExpressionParser.cpp @@ -0,0 +1,72 @@ +//===-- ExpressionParser.cpp ----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Expression/ExpressionParser.h" +#include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/ThreadPlanCallFunction.h" + +using namespace lldb; +using namespace lldb_private; + +Status ExpressionParser::PrepareForExecution( + addr_t &func_addr, addr_t &func_end, + std::shared_ptr<IRExecutionUnit> &execution_unit_sp, + ExecutionContext &exe_ctx, bool &can_interpret, + ExecutionPolicy execution_policy) { + Status status = + DoPrepareForExecution(func_addr, func_end, execution_unit_sp, exe_ctx, + can_interpret, execution_policy); + if (status.Success() && exe_ctx.GetProcessPtr() && exe_ctx.HasThreadScope()) + status = RunStaticInitializers(execution_unit_sp, exe_ctx); + + return status; +} + +Status +ExpressionParser::RunStaticInitializers(IRExecutionUnitSP &execution_unit_sp, + ExecutionContext &exe_ctx) { + Status err; + + if (!execution_unit_sp.get()) { + err.SetErrorString( + "can't run static initializers for a NULL execution unit"); + return err; + } + + if (!exe_ctx.HasThreadScope()) { + err.SetErrorString("can't run static initializers without a thread"); + return err; + } + + std::vector<addr_t> static_initializers; + + execution_unit_sp->GetStaticInitializers(static_initializers); + + for (addr_t static_initializer : static_initializers) { + EvaluateExpressionOptions options; + + ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction( + exe_ctx.GetThreadRef(), Address(static_initializer), CompilerType(), + llvm::ArrayRef<addr_t>(), options)); + + DiagnosticManager execution_errors; + ExpressionResults results = + exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan( + exe_ctx, call_static_initializer, options, execution_errors); + + if (results != eExpressionCompleted) { + err.SetErrorStringWithFormat("couldn't run static initializer: %s", + execution_errors.GetString().c_str()); + return err; + } + } + + return err; +} diff --git a/contrib/llvm-project/lldb/source/Expression/FunctionCaller.cpp b/contrib/llvm-project/lldb/source/Expression/FunctionCaller.cpp index ffadbf9b32ec..5ac2b0681ebb 100644 --- a/contrib/llvm-project/lldb/source/Expression/FunctionCaller.cpp +++ b/contrib/llvm-project/lldb/source/Expression/FunctionCaller.cpp @@ -67,27 +67,25 @@ bool FunctionCaller::WriteFunctionWrapper( Process *process = exe_ctx.GetProcessPtr(); if (!process) { - diagnostic_manager.Printf(eDiagnosticSeverityError, "no process."); + diagnostic_manager.Printf(lldb::eSeverityError, "no process."); return false; } lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock()); if (process != jit_process_sp.get()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, - "process does not match the stored process."); + diagnostic_manager.Printf(lldb::eSeverityError, + "process does not match the stored process."); return false; } if (process->GetState() != lldb::eStateStopped) { - diagnostic_manager.Printf(eDiagnosticSeverityError, - "process is not stopped"); + diagnostic_manager.Printf(lldb::eSeverityError, "process is not stopped"); return false; } if (!m_compiled) { - diagnostic_manager.Printf(eDiagnosticSeverityError, - "function not compiled"); + diagnostic_manager.Printf(lldb::eSeverityError, "function not compiled"); return false; } @@ -101,7 +99,7 @@ bool FunctionCaller::WriteFunctionWrapper( can_interpret, eExecutionPolicyAlways)); if (!jit_error.Success()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "Error in PrepareForExecution: %s.", jit_error.AsCString()); return false; @@ -144,7 +142,7 @@ bool FunctionCaller::WriteFunctionArguments( // All the information to reconstruct the struct is provided by the // StructExtractor. if (!m_struct_valid) { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "Argument information was not correctly " "parsed, so the function cannot be called."); return false; @@ -192,7 +190,7 @@ bool FunctionCaller::WriteFunctionArguments( size_t num_args = arg_values.GetSize(); if (num_args != m_arg_values.GetSize()) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "Wrong number of arguments - was: %" PRIu64 " should be: %" PRIu64 "", (uint64_t)num_args, (uint64_t)m_arg_values.GetSize()); return false; @@ -231,11 +229,11 @@ bool FunctionCaller::InsertFunction(ExecutionContext &exe_ctx, // the caller, we need to be stopped. Process *process = exe_ctx.GetProcessPtr(); if (!process) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "no process"); + diagnostic_manager.PutString(lldb::eSeverityError, "no process"); return false; } if (process->GetState() != lldb::eStateStopped) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "process running"); + diagnostic_manager.PutString(lldb::eSeverityError, "process running"); return false; } if (CompileFunction(exe_ctx.GetThreadSP(), diagnostic_manager) != 0) @@ -267,8 +265,7 @@ lldb::ThreadPlanSP FunctionCaller::GetThreadPlanToCallFunction( Thread *thread = exe_ctx.GetThreadPtr(); if (thread == nullptr) { diagnostic_manager.PutString( - eDiagnosticSeverityError, - "Can't call a function without a valid thread."); + lldb::eSeverityError, "Can't call a function without a valid thread."); return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Expression/IRExecutionUnit.cpp b/contrib/llvm-project/lldb/source/Expression/IRExecutionUnit.cpp index 0682746e448e..f22070442362 100644 --- a/contrib/llvm-project/lldb/source/Expression/IRExecutionUnit.cpp +++ b/contrib/llvm-project/lldb/source/Expression/IRExecutionUnit.cpp @@ -201,7 +201,7 @@ Status IRExecutionUnit::DisassembleFunction(Stream &stream, UINT32_MAX, false, false); InstructionList &instruction_list = disassembler_sp->GetInstructionList(); - instruction_list.Dump(&stream, true, true, /*show_control_flow_kind=*/true, + instruction_list.Dump(&stream, true, true, /*show_control_flow_kind=*/false, &exe_ctx); return ret; @@ -212,18 +212,17 @@ struct IRExecDiagnosticHandler : public llvm::DiagnosticHandler { Status *err; IRExecDiagnosticHandler(Status *err) : err(err) {} bool handleDiagnostics(const llvm::DiagnosticInfo &DI) override { - if (DI.getKind() == llvm::DK_SrcMgr) { + if (DI.getSeverity() == llvm::DS_Error) { const auto &DISM = llvm::cast<llvm::DiagnosticInfoSrcMgr>(DI); if (err && err->Success()) { err->SetErrorToGenericError(); err->SetErrorStringWithFormat( - "Inline assembly error: %s", + "IRExecution error: %s", DISM.getSMDiag().getMessage().str().c_str()); } - return true; } - return false; + return true; } }; } // namespace @@ -432,7 +431,9 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr, } m_failed_lookups.clear(); - + ss.PutCString( + "\nHint: The expression tried to call a function that is not present " + "in the target, perhaps because it was optimized out by the compiler."); error.SetErrorString(ss.GetString()); return; @@ -533,63 +534,63 @@ lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName( } if (!name.empty()) { - if (name.equals("__text") || name.equals(".text")) + if (name == "__text" || name == ".text") sect_type = lldb::eSectionTypeCode; - else if (name.equals("__data") || name.equals(".data")) + else if (name == "__data" || name == ".data") sect_type = lldb::eSectionTypeCode; 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.equals("abbrev")) + if (dwarf_name == "abbrev") sect_type = lldb::eSectionTypeDWARFDebugAbbrev; - else if (dwarf_name.equals("aranges")) + else if (dwarf_name == "aranges") sect_type = lldb::eSectionTypeDWARFDebugAranges; - else if (dwarf_name.equals("addr")) + else if (dwarf_name == "addr") sect_type = lldb::eSectionTypeDWARFDebugAddr; break; case 'f': - if (dwarf_name.equals("frame")) + if (dwarf_name == "frame") sect_type = lldb::eSectionTypeDWARFDebugFrame; break; case 'i': - if (dwarf_name.equals("info")) + if (dwarf_name == "info") sect_type = lldb::eSectionTypeDWARFDebugInfo; break; case 'l': - if (dwarf_name.equals("line")) + if (dwarf_name == "line") sect_type = lldb::eSectionTypeDWARFDebugLine; - else if (dwarf_name.equals("loc")) + else if (dwarf_name == "loc") sect_type = lldb::eSectionTypeDWARFDebugLoc; - else if (dwarf_name.equals("loclists")) + else if (dwarf_name == "loclists") sect_type = lldb::eSectionTypeDWARFDebugLocLists; break; case 'm': - if (dwarf_name.equals("macinfo")) + if (dwarf_name == "macinfo") sect_type = lldb::eSectionTypeDWARFDebugMacInfo; break; case 'p': - if (dwarf_name.equals("pubnames")) + if (dwarf_name == "pubnames") sect_type = lldb::eSectionTypeDWARFDebugPubNames; - else if (dwarf_name.equals("pubtypes")) + else if (dwarf_name == "pubtypes") sect_type = lldb::eSectionTypeDWARFDebugPubTypes; break; case 's': - if (dwarf_name.equals("str")) + if (dwarf_name == "str") sect_type = lldb::eSectionTypeDWARFDebugStr; - else if (dwarf_name.equals("str_offsets")) + else if (dwarf_name == "str_offsets") sect_type = lldb::eSectionTypeDWARFDebugStrOffsets; break; case 'r': - if (dwarf_name.equals("ranges")) + if (dwarf_name == "ranges") sect_type = lldb::eSectionTypeDWARFDebugRanges; break; @@ -598,7 +599,7 @@ lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName( } } else if (name.starts_with("__apple_") || name.starts_with(".apple_")) sect_type = lldb::eSectionTypeInvalid; - else if (name.equals("__objc_imageinfo")) + else if (name == "__objc_imageinfo") sect_type = lldb::eSectionTypeOther; } return sect_type; diff --git a/contrib/llvm-project/lldb/source/Expression/IRInterpreter.cpp b/contrib/llvm-project/lldb/source/Expression/IRInterpreter.cpp index df0292270866..5b670067b5c4 100644 --- a/contrib/llvm-project/lldb/source/Expression/IRInterpreter.cpp +++ b/contrib/llvm-project/lldb/source/Expression/IRInterpreter.cpp @@ -264,7 +264,7 @@ public: lldb_private::ConstString name(constant_func->getName()); bool missing_weak = false; lldb::addr_t addr = m_execution_unit.FindSymbol(name, missing_weak); - if (addr == LLDB_INVALID_ADDRESS || missing_weak) + if (addr == LLDB_INVALID_ADDRESS) return false; value = APInt(m_target_data.getPointerSizeInBits(), addr); return true; diff --git a/contrib/llvm-project/lldb/source/Expression/LLVMUserExpression.cpp b/contrib/llvm-project/lldb/source/Expression/LLVMUserExpression.cpp index 9c31cc84bf8f..b4fdfc4d1fa8 100644 --- a/contrib/llvm-project/lldb/source/Expression/LLVMUserExpression.cpp +++ b/contrib/llvm-project/lldb/source/Expression/LLVMUserExpression.cpp @@ -42,7 +42,7 @@ char LLVMUserExpression::ID; LLVMUserExpression::LLVMUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, + SourceLanguage language, ResultType desired_type, const EvaluateExpressionOptions &options) : UserExpression(exe_scope, expr, prefix, language, desired_type, options), @@ -73,7 +73,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, if (m_jit_start_addr == LLDB_INVALID_ADDRESS && !m_can_interpret) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "Expression can't be run, because there is no JIT compiled function"); return lldb::eExpressionSetupError; } @@ -83,7 +83,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, if (!PrepareToExecuteJITExpression(diagnostic_manager, exe_ctx, struct_address)) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__); return lldb::eExpressionSetupError; @@ -98,8 +98,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, if (!module || !function) { diagnostic_manager.PutString( - eDiagnosticSeverityError, - "supposed to interpret, but nothing is there"); + lldb::eSeverityError, "supposed to interpret, but nothing is there"); return lldb::eExpressionSetupError; } @@ -108,7 +107,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, std::vector<lldb::addr_t> args; if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "errored out in %s, couldn't AddArguments", __FUNCTION__); return lldb::eExpressionSetupError; @@ -122,14 +121,14 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, function_stack_top, exe_ctx, options.GetTimeout()); if (!interpreter_error.Success()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "supposed to interpret, but failed: %s", interpreter_error.AsCString()); return lldb::eExpressionDiscarded; } } else { if (!exe_ctx.HasThreadScope()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "%s called with no thread selected", __FUNCTION__); return lldb::eExpressionSetupError; @@ -144,7 +143,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, std::vector<lldb::addr_t> args; if (!AddArguments(exe_ctx, args, struct_address, diagnostic_manager)) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "errored out in %s, couldn't AddArguments", __FUNCTION__); return lldb::eExpressionSetupError; @@ -156,7 +155,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, StreamString ss; if (!call_plan_sp || !call_plan_sp->ValidatePlan(&ss)) { - diagnostic_manager.PutString(eDiagnosticSeverityError, ss.GetString()); + diagnostic_manager.PutString(lldb::eSeverityError, ss.GetString()); return lldb::eExpressionSetupError; } @@ -194,11 +193,11 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, error_desc = real_stop_info_sp->GetDescription(); } if (error_desc) - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "Execution was interrupted, reason: %s.", error_desc); else - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "Execution was interrupted."); if ((execution_result == lldb::eExpressionInterrupted && @@ -221,7 +220,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, return execution_result; } else if (execution_result == lldb::eExpressionStoppedForDebug) { diagnostic_manager.PutString( - eDiagnosticSeverityRemark, + lldb::eSeverityInfo, "Execution was halted at the first instruction of the expression " "function because \"debug\" was requested.\n" "Use \"thread return -x\" to return to the state before expression " @@ -229,7 +228,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, return execution_result; } else if (execution_result == lldb::eExpressionThreadVanished) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "Couldn't complete execution; the thread " "on which the expression was being run: 0x%" PRIx64 " exited during its execution.", @@ -237,7 +236,7 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, return execution_result; } else if (execution_result != lldb::eExpressionCompleted) { diagnostic_manager.Printf( - eDiagnosticSeverityError, "Couldn't execute function; result was %s", + lldb::eSeverityError, "Couldn't execute function; result was %s", Process::ExecutionResultAsCString(execution_result)); return execution_result; } @@ -261,7 +260,7 @@ bool LLVMUserExpression::FinalizeJITExecution( "after execution --"); if (!m_dematerializer_sp) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "Couldn't apply expression side effects : no " "dematerializer is present"); return false; @@ -273,7 +272,7 @@ bool LLVMUserExpression::FinalizeJITExecution( function_stack_top); if (!dematerialize_error.Success()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "Couldn't apply expression side effects : %s", dematerialize_error.AsCString("unknown error")); return false; @@ -299,7 +298,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression( if (!LockAndCheckContext(exe_ctx, target, process, frame)) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "The context has changed before we could JIT the expression!"); return false; } @@ -322,7 +321,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression( if (!alloc_error.Success()) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "Couldn't allocate space for materialized struct: %s", alloc_error.AsCString()); return false; @@ -354,7 +353,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression( if (!alloc_error.Success()) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "Couldn't allocate space for the stack frame: %s", alloc_error.AsCString()); return false; @@ -367,7 +366,7 @@ bool LLVMUserExpression::PrepareToExecuteJITExpression( frame, *m_execution_unit_sp, struct_address, materialize_error); if (!materialize_error.Success()) { - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "Couldn't materialize: %s", materialize_error.AsCString()); return false; diff --git a/contrib/llvm-project/lldb/source/Expression/UserExpression.cpp b/contrib/llvm-project/lldb/source/Expression/UserExpression.cpp index c181712a2f0b..b78f43995767 100644 --- a/contrib/llvm-project/lldb/source/Expression/UserExpression.cpp +++ b/contrib/llvm-project/lldb/source/Expression/UserExpression.cpp @@ -39,6 +39,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" +#include "llvm/BinaryFormat/Dwarf.h" using namespace lldb_private; @@ -46,8 +47,7 @@ char UserExpression::ID; UserExpression::UserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, - ResultType desired_type, + SourceLanguage language, ResultType desired_type, const EvaluateExpressionOptions &options) : Expression(exe_scope), m_expr_text(std::string(expr)), m_expr_prefix(std::string(prefix)), m_language(language), @@ -176,7 +176,7 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, } lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); - lldb::LanguageType language = options.GetLanguage(); + SourceLanguage language = options.GetLanguage(); const ResultType desired_type = options.DoesCoerceToId() ? UserExpression::eResultTypeId : UserExpression::eResultTypeAny; @@ -242,7 +242,7 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, // If the language was not specified in the expression command, set it to the // language in the target's properties if specified, else default to the // langage for the frame. - if (language == lldb::eLanguageTypeUnknown) { + if (!language) { if (target->GetLanguage() != lldb::eLanguageTypeUnknown) language = target->GetLanguage(); else if (StackFrame *frame = exe_ctx.GetFramePtr()) @@ -300,6 +300,8 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, target->GetUserExpressionForLanguage( fixed_expression->c_str(), full_prefix, language, desired_type, options, ctx_obj, error)); + if (!fixed_expression_sp) + break; DiagnosticManager fixed_diagnostic_manager; parse_success = fixed_expression_sp->Parse( fixed_diagnostic_manager, exe_ctx, execution_policy, @@ -308,17 +310,16 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, diagnostic_manager.Clear(); user_expression_sp = fixed_expression_sp; break; + } + // The fixed expression also didn't parse. Let's check for any new + // fixits we could try. + if (!fixed_expression_sp->GetFixedText().empty()) { + *fixed_expression = fixed_expression_sp->GetFixedText().str(); } else { - // The fixed expression also didn't parse. Let's check for any new - // Fix-Its we could try. - if (!fixed_expression_sp->GetFixedText().empty()) { - *fixed_expression = fixed_expression_sp->GetFixedText().str(); - } else { - // Fixed expression didn't compile without a fixit, don't retry and - // don't tell the user about it. - fixed_expression->clear(); - break; - } + // Fixed expression didn't compile without a fixit, don't retry and + // don't tell the user about it. + fixed_expression->clear(); + break; } } } @@ -384,7 +385,8 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); - result_valobj_sp->SetPreferredDisplayLanguage(language); + result_valobj_sp->SetPreferredDisplayLanguage( + language.AsLanguageType()); LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed " @@ -426,7 +428,8 @@ UserExpression::Execute(DiagnosticManager &diagnostic_manager, Target *target = exe_ctx.GetTargetPtr(); if (options.GetSuppressPersistentResult() && result_var && target) { if (auto *persistent_state = - target->GetPersistentExpressionStateForLanguage(m_language)) + target->GetPersistentExpressionStateForLanguage( + m_language.AsLanguageType())) persistent_state->RemovePersistentVariable(result_var); } return expr_result; diff --git a/contrib/llvm-project/lldb/source/Expression/UtilityFunction.cpp b/contrib/llvm-project/lldb/source/Expression/UtilityFunction.cpp index d7a3c9d41d04..7b34c2c2ff76 100644 --- a/contrib/llvm-project/lldb/source/Expression/UtilityFunction.cpp +++ b/contrib/llvm-project/lldb/source/Expression/UtilityFunction.cpp @@ -80,8 +80,8 @@ FunctionCaller *UtilityFunction::MakeFunctionCaller( name.append("-caller"); m_caller_up.reset(process_sp->GetTarget().GetFunctionCallerForLanguage( - Language(), return_type, impl_code_address, arg_value_list, name.c_str(), - error)); + Language().AsLanguageType(), return_type, impl_code_address, + arg_value_list, name.c_str(), error)); if (error.Fail()) { return nullptr; diff --git a/contrib/llvm-project/lldb/source/Host/common/Alarm.cpp b/contrib/llvm-project/lldb/source/Host/common/Alarm.cpp new file mode 100644 index 000000000000..afc770d20d7b --- /dev/null +++ b/contrib/llvm-project/lldb/source/Host/common/Alarm.cpp @@ -0,0 +1,222 @@ +//===-- Alarm.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Alarm.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; + +Alarm::Alarm(Duration timeout, bool run_callback_on_exit) + : m_timeout(timeout), m_run_callbacks_on_exit(run_callback_on_exit) { + StartAlarmThread(); +} + +Alarm::~Alarm() { StopAlarmThread(); } + +Alarm::Handle Alarm::Create(std::function<void()> callback) { + // Gracefully deal with the unlikely event that the alarm thread failed to + // launch. + if (!AlarmThreadRunning()) + return INVALID_HANDLE; + + // Compute the next expiration before we take the lock. This ensures that + // waiting on the lock doesn't eat into the timeout. + const TimePoint expiration = GetNextExpiration(); + + Handle handle = INVALID_HANDLE; + + { + std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex); + + // Create a new unique entry and remember its handle. + m_entries.emplace_back(callback, expiration); + handle = m_entries.back().handle; + + // Tell the alarm thread we need to recompute the next alarm. + m_recompute_next_alarm = true; + } + + m_alarm_cv.notify_one(); + return handle; +} + +bool Alarm::Restart(Handle handle) { + // Gracefully deal with the unlikely event that the alarm thread failed to + // launch. + if (!AlarmThreadRunning()) + return false; + + // Compute the next expiration before we take the lock. This ensures that + // waiting on the lock doesn't eat into the timeout. + const TimePoint expiration = GetNextExpiration(); + + { + std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex); + + // Find the entry corresponding to the given handle. + const auto it = + std::find_if(m_entries.begin(), m_entries.end(), + [handle](Entry &entry) { return entry.handle == handle; }); + if (it == m_entries.end()) + return false; + + // Update the expiration. + it->expiration = expiration; + + // Tell the alarm thread we need to recompute the next alarm. + m_recompute_next_alarm = true; + } + + m_alarm_cv.notify_one(); + return true; +} + +bool Alarm::Cancel(Handle handle) { + // Gracefully deal with the unlikely event that the alarm thread failed to + // launch. + if (!AlarmThreadRunning()) + return false; + + { + std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex); + + const auto it = + std::find_if(m_entries.begin(), m_entries.end(), + [handle](Entry &entry) { return entry.handle == handle; }); + + if (it == m_entries.end()) + return false; + + m_entries.erase(it); + } + + // No need to notify the alarm thread. This only affects the alarm thread if + // we removed the entry that corresponds to the next alarm. If that's the + // case, the thread will wake up as scheduled, find no expired events, and + // recompute the next alarm time. + return true; +} + +Alarm::Entry::Entry(Alarm::Callback callback, Alarm::TimePoint expiration) + : handle(Alarm::GetNextUniqueHandle()), callback(std::move(callback)), + expiration(std::move(expiration)) {} + +void Alarm::StartAlarmThread() { + if (!m_alarm_thread.IsJoinable()) { + llvm::Expected<HostThread> alarm_thread = ThreadLauncher::LaunchThread( + "lldb.debugger.alarm-thread", [this] { return AlarmThread(); }, + 8 * 1024 * 1024); // Use larger 8MB stack for this thread + if (alarm_thread) { + m_alarm_thread = *alarm_thread; + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Host), alarm_thread.takeError(), + "failed to launch host thread: {0}"); + } + } +} + +void Alarm::StopAlarmThread() { + if (m_alarm_thread.IsJoinable()) { + { + std::lock_guard<std::mutex> alarm_guard(m_alarm_mutex); + m_exit = true; + } + m_alarm_cv.notify_one(); + m_alarm_thread.Join(nullptr); + } +} + +bool Alarm::AlarmThreadRunning() { return m_alarm_thread.IsJoinable(); } + +lldb::thread_result_t Alarm::AlarmThread() { + bool exit = false; + std::optional<TimePoint> next_alarm; + + const auto predicate = [this] { return m_exit || m_recompute_next_alarm; }; + + while (!exit) { + // Synchronization between the main thread and the alarm thread using a + // mutex and condition variable. There are 2 reasons the thread can wake up: + // + // 1. The timeout for the next alarm expired. + // + // 2. The condition variable is notified that one of our shared variables + // (see predicate) was modified. Either the thread is asked to shut down + // or a new alarm came in and we need to recompute the next timeout. + // + // Below we only deal with the timeout expiring and fall through for dealing + // with the rest. + llvm::SmallVector<Callback, 1> callbacks; + { + std::unique_lock<std::mutex> alarm_lock(m_alarm_mutex); + if (next_alarm) { + if (!m_alarm_cv.wait_until(alarm_lock, *next_alarm, predicate)) { + // The timeout for the next alarm expired. + + // Clear the next timeout to signal that we need to recompute the next + // timeout. + next_alarm.reset(); + + // Iterate over all the callbacks. Call the ones that have expired + // and remove them from the list. + const TimePoint now = std::chrono::system_clock::now(); + auto it = m_entries.begin(); + while (it != m_entries.end()) { + if (it->expiration <= now) { + callbacks.emplace_back(std::move(it->callback)); + it = m_entries.erase(it); + } else { + it++; + } + } + } + } else { + m_alarm_cv.wait(alarm_lock, predicate); + } + + // Fall through after waiting on the condition variable. At this point + // either the predicate is true or we woke up because an alarm expired. + + // The alarm thread is shutting down. + if (m_exit) { + exit = true; + if (m_run_callbacks_on_exit) { + for (Entry &entry : m_entries) + callbacks.emplace_back(std::move(entry.callback)); + } + } + + // A new alarm was added or an alarm expired. Either way we need to + // recompute when this thread should wake up for the next alarm. + if (m_recompute_next_alarm || !next_alarm) { + for (Entry &entry : m_entries) { + if (!next_alarm || entry.expiration < *next_alarm) + next_alarm = entry.expiration; + } + m_recompute_next_alarm = false; + } + } + + // Outside the lock, call the callbacks. + for (Callback &callback : callbacks) + callback(); + } + return {}; +} + +Alarm::TimePoint Alarm::GetNextExpiration() const { + return std::chrono::system_clock::now() + m_timeout; +} + +Alarm::Handle Alarm::GetNextUniqueHandle() { + static std::atomic<Handle> g_next_handle = 1; + return g_next_handle++; +} diff --git a/contrib/llvm-project/lldb/source/Host/common/Editline.cpp b/contrib/llvm-project/lldb/source/Host/common/Editline.cpp index ce707e530d00..561ec228cdb2 100644 --- a/contrib/llvm-project/lldb/source/Host/common/Editline.cpp +++ b/contrib/llvm-project/lldb/source/Host/common/Editline.cpp @@ -31,20 +31,6 @@ using namespace lldb_private; using namespace lldb_private::line_editor; -// Workaround for what looks like an OS X-specific issue, but other platforms -// may benefit from something similar if issues arise. The libedit library -// doesn't explicitly initialize the curses termcap library, which it gets away -// with until TERM is set to VT100 where it stumbles over an implementation -// assumption that may not exist on other platforms. The setupterm() function -// would normally require headers that don't work gracefully in this context, -// so the function declaration has been hoisted here. -#if defined(__APPLE__) -extern "C" { -int setupterm(char *term, int fildes, int *errret); -} -#define USE_SETUPTERM_WORKAROUND -#endif - // Editline uses careful cursor management to achieve the illusion of editing a // multi-line block of text with a single line editor. Preserving this // illusion requires fairly careful management of cursor state. Read and @@ -1029,8 +1015,11 @@ unsigned char Editline::TabCommand(int ch) { case CompletionMode::Normal: { std::string to_add = completion.GetCompletion(); // Terminate the current argument with a quote if it started with a quote. - if (!request.GetParsedLine().empty() && request.GetParsedArg().IsQuoted()) + Args &parsedLine = request.GetParsedLine(); + if (!parsedLine.empty() && request.GetCursorIndex() < parsedLine.size() && + request.GetParsedArg().IsQuoted()) { to_add.push_back(request.GetParsedArg().GetQuoteChar()); + } to_add.push_back(' '); el_deletestr(m_editline, request.GetCursorArgumentPrefix().size()); el_insertstr(m_editline, to_add.c_str()); @@ -1399,35 +1388,6 @@ Editline::Editline(const char *editline_name, FILE *input_file, // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; m_history_sp = EditlineHistory::GetHistory(m_editor_name); - -#ifdef USE_SETUPTERM_WORKAROUND - if (m_output_file) { - const int term_fd = fileno(m_output_file); - if (term_fd != -1) { - static std::recursive_mutex *g_init_terminal_fds_mutex_ptr = nullptr; - static std::set<int> *g_init_terminal_fds_ptr = nullptr; - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, [&]() { - g_init_terminal_fds_mutex_ptr = - new std::recursive_mutex(); // NOTE: Leak to avoid C++ destructor - // chain issues - g_init_terminal_fds_ptr = new std::set<int>(); // NOTE: Leak to avoid - // C++ destructor chain - // issues - }); - - // We must make sure to initialize the terminal a given file descriptor - // only once. If we do this multiple times, we start leaking memory. - std::lock_guard<std::recursive_mutex> guard( - *g_init_terminal_fds_mutex_ptr); - if (g_init_terminal_fds_ptr->find(term_fd) == - g_init_terminal_fds_ptr->end()) { - g_init_terminal_fds_ptr->insert(term_fd); - setupterm((char *)0, term_fd, (int *)0); - } - } - } -#endif } Editline::~Editline() { @@ -1594,6 +1554,7 @@ bool Editline::GetLines(int first_line_number, StringList &lines, void Editline::PrintAsync(Stream *stream, const char *s, size_t len) { std::lock_guard<std::recursive_mutex> guard(m_output_mutex); if (m_editor_status == EditorStatus::Editing) { + SaveEditedLine(); MoveCursor(CursorLocation::EditingCursor, CursorLocation::BlockStart); fprintf(m_output_file, ANSI_CLEAR_BELOW); } diff --git a/contrib/llvm-project/lldb/source/Host/common/Host.cpp b/contrib/llvm-project/lldb/source/Host/common/Host.cpp index f4cec97f5af6..06ccc0e2b342 100644 --- a/contrib/llvm-project/lldb/source/Host/common/Host.cpp +++ b/contrib/llvm-project/lldb/source/Host/common/Host.cpp @@ -89,7 +89,40 @@ using namespace lldb; using namespace lldb_private; #if !defined(__APPLE__) -void Host::SystemLog(llvm::StringRef message) { llvm::errs() << message; } +#if !defined(_WIN32) +#include <syslog.h> +void Host::SystemLog(Severity severity, llvm::StringRef message) { + static llvm::once_flag g_openlog_once; + llvm::call_once(g_openlog_once, [] { + openlog("lldb", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_USER); + }); + int level = LOG_DEBUG; + switch (severity) { + case lldb::eSeverityInfo: + level = LOG_INFO; + break; + case lldb::eSeverityWarning: + level = LOG_WARNING; + break; + case lldb::eSeverityError: + level = LOG_ERR; + break; + } + syslog(level, "%s", message.data()); +} +#else +void Host::SystemLog(Severity severity, llvm::StringRef message) { + switch (severity) { + case lldb::eSeverityInfo: + case lldb::eSeverityWarning: + llvm::outs() << message; + break; + case lldb::eSeverityError: + llvm::errs() << message; + break; + } +} +#endif #endif #if !defined(__APPLE__) && !defined(_WIN32) @@ -618,5 +651,5 @@ char SystemLogHandler::ID; SystemLogHandler::SystemLogHandler() {} void SystemLogHandler::Emit(llvm::StringRef message) { - Host::SystemLog(message); + Host::SystemLog(lldb::eSeverityInfo, message); } diff --git a/contrib/llvm-project/lldb/source/Host/common/Socket.cpp b/contrib/llvm-project/lldb/source/Host/common/Socket.cpp index bd0c127a0895..f9911cf136cb 100644 --- a/contrib/llvm-project/lldb/source/Host/common/Socket.cpp +++ b/contrib/llvm-project/lldb/source/Host/common/Socket.cpp @@ -87,8 +87,7 @@ llvm::Error Socket::Initialize() { if (err == 0) { if (wsaData.wVersion < wVersion) { WSACleanup(); - return llvm::make_error<llvm::StringError>( - "WSASock version is not expected.", llvm::inconvertibleErrorCode()); + return llvm::createStringError("WSASock version is not expected."); } } else { return llvm::errorCodeToError(llvm::mapWindowsError(::WSAGetLastError())); diff --git a/contrib/llvm-project/lldb/source/Host/posix/PipePosix.cpp b/contrib/llvm-project/lldb/source/Host/posix/PipePosix.cpp index afd3fe39059a..f35c348990df 100644 --- a/contrib/llvm-project/lldb/source/Host/posix/PipePosix.cpp +++ b/contrib/llvm-project/lldb/source/Host/posix/PipePosix.cpp @@ -108,7 +108,7 @@ Status PipePosix::CreateNew(bool child_processes_inherit) { } Status PipePosix::CreateNew(llvm::StringRef name, bool child_process_inherit) { - std::scoped_lock<std::mutex, std::mutex> (m_read_mutex, m_write_mutex); + std::scoped_lock<std::mutex, std::mutex> guard(m_read_mutex, m_write_mutex); if (CanReadUnlocked() || CanWriteUnlocked()) return Status("Pipe is already opened"); @@ -146,7 +146,7 @@ Status PipePosix::CreateWithUniqueName(llvm::StringRef prefix, Status PipePosix::OpenAsReader(llvm::StringRef name, bool child_process_inherit) { - std::scoped_lock<std::mutex, std::mutex> (m_read_mutex, m_write_mutex); + std::scoped_lock<std::mutex, std::mutex> guard(m_read_mutex, m_write_mutex); if (CanReadUnlocked() || CanWriteUnlocked()) return Status("Pipe is already opened"); diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp index 00651df48b62..fc07168b6c0a 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include <chrono> #include <cstdlib> #include <limits> #include <memory> @@ -32,7 +33,7 @@ #include "Commands/CommandObjectQuit.h" #include "Commands/CommandObjectRegexCommand.h" #include "Commands/CommandObjectRegister.h" -#include "Commands/CommandObjectScript.h" +#include "Commands/CommandObjectScripting.h" #include "Commands/CommandObjectSession.h" #include "Commands/CommandObjectSettings.h" #include "Commands/CommandObjectSource.h" @@ -47,10 +48,12 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Host/StreamFile.h" +#include "lldb/Utility/ErrorMessages.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timer.h" #include "lldb/Host/Config.h" @@ -119,15 +122,15 @@ enum { #include "InterpreterPropertiesEnum.inc" }; -ConstString &CommandInterpreter::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.commandInterpreter"); +llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter"); return class_name; } CommandInterpreter::CommandInterpreter(Debugger &debugger, bool synchronous_execution) : Broadcaster(debugger.GetBroadcasterManager(), - CommandInterpreter::GetStaticBroadcasterClass().AsCString()), + CommandInterpreter::GetStaticBroadcasterClass().str()), Properties( OptionValuePropertiesSP(new OptionValueProperties("interpreter"))), IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), @@ -161,6 +164,17 @@ void CommandInterpreter::SetPromptOnQuit(bool enable) { SetPropertyAtIndex(idx, enable); } +bool CommandInterpreter::GetSaveTranscript() const { + const uint32_t idx = ePropertySaveTranscript; + return GetPropertyAtIndexAs<bool>( + idx, g_interpreter_properties[idx].default_uint_value != 0); +} + +void CommandInterpreter::SetSaveTranscript(bool enable) { + const uint32_t idx = ePropertySaveTranscript; + SetPropertyAtIndex(idx, enable); +} + bool CommandInterpreter::GetSaveSessionOnQuit() const { const uint32_t idx = ePropertySaveSessionOnQuit; return GetPropertyAtIndexAs<bool>( @@ -504,6 +518,15 @@ void CommandInterpreter::Initialize() { AddAlias("re", cmd_obj_sp); } + cmd_obj_sp = GetCommandSPExact("scripting run"); + if (cmd_obj_sp) { + AddAlias("sc", cmd_obj_sp); + AddAlias("scr", cmd_obj_sp); + AddAlias("scri", cmd_obj_sp); + AddAlias("scrip", cmd_obj_sp); + AddAlias("script", cmd_obj_sp); + } + cmd_obj_sp = GetCommandSPExact("session history"); if (cmd_obj_sp) { AddAlias("history", cmd_obj_sp); @@ -555,7 +578,7 @@ void CommandInterpreter::LoadCommandDictionary() { REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess); REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit); REGISTER_COMMAND_OBJECT("register", CommandObjectRegister); - REGISTER_COMMAND_OBJECT("script", CommandObjectScript); + REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting); REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings); REGISTER_COMMAND_OBJECT("session", CommandObjectSession); REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource); @@ -816,11 +839,11 @@ void CommandInterpreter::LoadCommandDictionary() { std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up( new CommandObjectRegexCommand( *this, "_regexp-bt", - "Show the current thread's call stack. Any numeric argument " - "displays at most that many " - "frames. The argument 'all' displays all threads. Use 'settings" - " set frame-format' to customize the printing of individual frames " - "and 'settings set thread-format' to customize the thread header.", + "Show backtrace of the current thread's call stack. Any numeric " + "argument displays at most that many frames. The argument 'all' " + "displays all threads. Use 'settings set frame-format' to customize " + "the printing of individual frames and 'settings set thread-format' " + "to customize the thread header.", "bt [<digit> | all]", 0, false)); if (bt_regex_cmd_up) { // accept but don't document "bt -c <number>" -- before bt was a regex @@ -1804,51 +1827,8 @@ CommandInterpreter::PreprocessToken(std::string &expr_str) { error = expr_result_valobj_sp->GetError(); if (error.Success()) { - switch (expr_result) { - case eExpressionSetupError: - error.SetErrorStringWithFormat( - "expression setup error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionParseError: - error.SetErrorStringWithFormat( - "expression parse error for the expression '%s'", expr_str.c_str()); - break; - case eExpressionResultUnavailable: - error.SetErrorStringWithFormat( - "expression error fetching result for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionCompleted: - break; - case eExpressionDiscarded: - error.SetErrorStringWithFormat( - "expression discarded for the expression '%s'", expr_str.c_str()); - break; - case eExpressionInterrupted: - error.SetErrorStringWithFormat( - "expression interrupted for the expression '%s'", expr_str.c_str()); - break; - case eExpressionHitBreakpoint: - error.SetErrorStringWithFormat( - "expression hit breakpoint for the expression '%s'", - expr_str.c_str()); - break; - case eExpressionTimedOut: - error.SetErrorStringWithFormat( - "expression timed out for the expression '%s'", expr_str.c_str()); - break; - case eExpressionStoppedForDebug: - error.SetErrorStringWithFormat("expression stop at entry point " - "for debugging for the " - "expression '%s'", - expr_str.c_str()); - break; - case eExpressionThreadVanished: - error.SetErrorStringWithFormat( - "expression thread vanished for the expression '%s'", - expr_str.c_str()); - break; - } + std::string result = lldb_private::toString(expr_result); + error.SetErrorString(result + "for the expression '" + expr_str + "'"); } return error; } @@ -1889,7 +1869,21 @@ bool CommandInterpreter::HandleCommand(const char *command_line, else add_to_history = (lazy_add_to_history == eLazyBoolYes); - m_transcript_stream << "(lldb) " << command_line << '\n'; + // The same `transcript_item` will be used below to add output and error of + // the command. + StructuredData::DictionarySP transcript_item; + if (GetSaveTranscript()) { + m_transcript_stream << "(lldb) " << command_line << '\n'; + + transcript_item = std::make_shared<StructuredData::Dictionary>(); + transcript_item->AddStringItem("command", command_line); + transcript_item->AddIntegerItem( + "timestampInEpochSeconds", + std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::system_clock::now().time_since_epoch()) + .count()); + m_transcript.AddItem(transcript_item); + } bool empty_command = false; bool comment_command = false; @@ -1994,7 +1988,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line, // Take care of things like setting up the history command & calling the // appropriate Execute method on the CommandObject, with the appropriate // arguments. - + StatsDuration execute_time; if (cmd_obj != nullptr) { bool generate_repeat_command = add_to_history; // If we got here when empty_command was true, then this command is a @@ -2035,14 +2029,33 @@ bool CommandInterpreter::HandleCommand(const char *command_line, log, "HandleCommand, command line after removing command name(s): '%s'", remainder.c_str()); + // To test whether or not transcript should be saved, `transcript_item` is + // used instead of `GetSaveTrasncript()`. This is because the latter will + // fail when the command is "settings set interpreter.save-transcript true". + if (transcript_item) { + transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName()); + transcript_item->AddStringItem("commandArguments", remainder); + } + + ElapsedTime elapsed(execute_time); cmd_obj->Execute(remainder.c_str(), result); } LLDB_LOGF(log, "HandleCommand, command %s", (result.Succeeded() ? "succeeded" : "did not succeed")); - m_transcript_stream << result.GetOutputData(); - m_transcript_stream << result.GetErrorData(); + // To test whether or not transcript should be saved, `transcript_item` is + // used instead of `GetSaveTrasncript()`. This is because the latter will + // fail when the command is "settings set interpreter.save-transcript true". + if (transcript_item) { + m_transcript_stream << result.GetOutputData(); + m_transcript_stream << result.GetErrorData(); + + transcript_item->AddStringItem("output", result.GetOutputData()); + transcript_item->AddStringItem("error", result.GetErrorData()); + transcript_item->AddFloatItem("durationInSeconds", + execute_time.get().count()); + } return result.Succeeded(); } @@ -2661,7 +2674,8 @@ enum { eHandleCommandFlagEchoCommentCommand = (1u << 3), eHandleCommandFlagPrintResult = (1u << 4), eHandleCommandFlagPrintErrors = (1u << 5), - eHandleCommandFlagStopOnCrash = (1u << 6) + eHandleCommandFlagStopOnCrash = (1u << 6), + eHandleCommandFlagAllowRepeats = (1u << 7) }; void CommandInterpreter::HandleCommandsFromFile( @@ -3055,8 +3069,8 @@ void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, } std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); - if (had_output && INTERRUPT_REQUESTED(GetDebugger(), - "Interrupted dumping command output")) + if (had_output && + INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output")) stream->Printf("\n... Interrupted.\n"); stream->Flush(); } @@ -3083,14 +3097,19 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, return; const bool is_interactive = io_handler.GetIsInteractive(); - if (!is_interactive) { + const bool allow_repeats = + io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats); + + if (!is_interactive && !allow_repeats) { // When we are not interactive, don't execute blank lines. This will happen // sourcing a commands file. We don't want blank lines to repeat the // previous command and cause any errors to occur (like redefining an // alias, get an error and stop parsing the commands file). + // But obey the AllowRepeats flag if the user has set it. if (line.empty()) return; - + } + if (!is_interactive) { // When using a non-interactive file handle (like when sourcing commands // from a file) we need to echo the command out so we don't just see the // command output and no command... @@ -3204,6 +3223,8 @@ bool CommandInterpreter::SaveTranscript( if (output_file == std::nullopt || output_file->empty()) { std::string now = llvm::to_string(std::chrono::system_clock::now()); std::replace(now.begin(), now.end(), ' ', '_'); + // Can't have file name with colons on Windows + std::replace(now.begin(), now.end(), ':', '-'); const std::string file_name = "lldb_session_" + now + ".log"; FileSpec save_location = GetSaveSessionDirectory(); @@ -3340,6 +3361,8 @@ CommandInterpreter::GetIOHandler(bool force_create, flags |= eHandleCommandFlagPrintResult; if (options->m_print_errors != eLazyBoolNo) flags |= eHandleCommandFlagPrintErrors; + if (options->m_allow_repeats == eLazyBoolYes) + flags |= eHandleCommandFlagAllowRepeats; } else { flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult | eHandleCommandFlagPrintErrors; @@ -3547,3 +3570,14 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, return cmd_obj; } + +llvm::json::Value CommandInterpreter::GetStatistics() { + llvm::json::Object stats; + for (const auto &command_usage : m_command_usages) + stats.try_emplace(command_usage.getKey(), command_usage.getValue()); + return stats; +} + +const StructuredData::Array &CommandInterpreter::GetTranscript() const { + return m_transcript; +} diff --git a/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp b/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp index 1ff9774a0da4..4634b75c6a33 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/CommandObject.cpp @@ -305,6 +305,43 @@ void CommandObject::HandleCompletion(CompletionRequest &request) { } } +void CommandObject::HandleArgumentCompletion( + CompletionRequest &request, OptionElementVector &opt_element_vector) { + size_t num_arg_entries = GetNumArgumentEntries(); + if (num_arg_entries != 1) + return; + + CommandArgumentEntry *entry_ptr = GetArgumentEntryAtIndex(0); + if (!entry_ptr) { + assert(entry_ptr && "We said there was one entry, but there wasn't."); + return; // Not worth crashing if asserts are off... + } + + CommandArgumentEntry &entry = *entry_ptr; + // For now, we only handle the simple case of one homogenous argument type. + if (entry.size() != 1) + return; + + // Look up the completion type, and if it has one, invoke it: + const CommandObject::ArgumentTableEntry *arg_entry = + FindArgumentDataByType(entry[0].arg_type); + const ArgumentRepetitionType repeat = entry[0].arg_repetition; + + if (arg_entry == nullptr || arg_entry->completion_type == lldb::eNoCompletion) + return; + + // FIXME: This should be handled higher in the Command Parser. + // Check the case where this command only takes one argument, and don't do + // the completion if we aren't on the first entry: + if (repeat == eArgRepeatPlain && request.GetCursorIndex() != 0) + return; + + lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), arg_entry->completion_type, request, nullptr); + +} + + bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word, bool search_short_help, bool search_long_help, @@ -355,6 +392,24 @@ bool CommandObject::ParseOptionsAndNotify(Args &args, return true; } +void CommandObject::AddSimpleArgumentList( + CommandArgumentType arg_type, ArgumentRepetitionType repetition_type) { + + CommandArgumentEntry arg_entry; + CommandArgumentData simple_arg; + + // Define the first (and only) variant of this arg. + simple_arg.arg_type = arg_type; + simple_arg.arg_repetition = repetition_type; + + // There is only one variant this argument could be; put it into the argument + // entry. + arg_entry.push_back(simple_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg_entry); +} + int CommandObject::GetNumArgumentEntries() { return m_arguments.size(); } CommandObject::CommandArgumentEntry * @@ -447,6 +502,23 @@ bool CommandObject::IsPairType(ArgumentRepetitionType arg_repeat_type) { (arg_repeat_type == eArgRepeatPairRangeOptional); } +std::optional<ArgumentRepetitionType> +CommandObject::ArgRepetitionFromString(llvm::StringRef string) { + return llvm::StringSwitch<ArgumentRepetitionType>(string) + .Case("plain", eArgRepeatPlain) + .Case("optional", eArgRepeatOptional) + .Case("plus", eArgRepeatPlus) + .Case("star", eArgRepeatStar) + .Case("range", eArgRepeatRange) + .Case("pair-plain", eArgRepeatPairPlain) + .Case("pair-optional", eArgRepeatPairOptional) + .Case("pair-plus", eArgRepeatPairPlus) + .Case("pair-star", eArgRepeatPairStar) + .Case("pair-range", eArgRepeatPairRange) + .Case("pair-range-optional", eArgRepeatPairRangeOptional) + .Default({}); +} + static CommandObject::CommandArgumentEntry OptSetFiltered(uint32_t opt_set_mask, CommandObject::CommandArgumentEntry &cmd_arg_entry) { @@ -640,20 +712,24 @@ void CommandObject::GenerateHelpText(Stream &output_strm) { } } -void CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg, - CommandArgumentType ID, - CommandArgumentType IDRange) { +void CommandObject::AddIDsArgumentData(CommandObject::IDType type) { + CommandArgumentEntry arg; CommandArgumentData id_arg; CommandArgumentData id_range_arg; // Create the first variant for the first (and only) argument for this // command. - id_arg.arg_type = ID; + switch (type) { + case eBreakpointArgs: + id_arg.arg_type = eArgTypeBreakpointID; + id_range_arg.arg_type = eArgTypeBreakpointIDRange; + break; + case eWatchpointArgs: + id_arg.arg_type = eArgTypeWatchpointID; + id_range_arg.arg_type = eArgTypeWatchpointIDRange; + break; + } id_arg.arg_repetition = eArgRepeatOptional; - - // Create the second variant for the first (and only) argument for this - // command. - id_range_arg.arg_type = IDRange; id_range_arg.arg_repetition = eArgRepeatOptional; // The first (and only) argument for this command could be either an id or an @@ -661,6 +737,7 @@ void CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg, // this command. arg.push_back(id_arg); arg.push_back(id_range_arg); + m_arguments.push_back(arg); } const char *CommandObject::GetArgumentTypeAsCString( @@ -748,6 +825,7 @@ void CommandObjectParsed::Execute(const char *args_string, Cleanup(); return; } + m_interpreter.IncreaseCommandUsage(*this); DoExecute(cmd_args, result); } } diff --git a/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td b/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td index 2155ee61ccff..a5fccbbca091 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td +++ b/contrib/llvm-project/lldb/source/Interpreter/InterpreterProperties.td @@ -9,6 +9,10 @@ let Definition = "interpreter" in { Global, DefaultTrue, Desc<"If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case.">; + def SaveTranscript: Property<"save-transcript", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, commands will be saved into a transcript buffer for user access.">; def SaveSessionOnQuit: Property<"save-session-on-quit", "Boolean">, Global, DefaultFalse, diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp index d13805a75ffb..105d4846da14 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/OptionArgParser.cpp @@ -9,7 +9,9 @@ #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" @@ -33,6 +35,20 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value, return fail_value; } +llvm::Expected<bool> OptionArgParser::ToBoolean(llvm::StringRef option_name, + llvm::StringRef option_arg) { + bool parse_success; + const bool option_value = + ToBoolean(option_arg, false /* doesn't matter */, &parse_success); + if (parse_success) + return option_value; + else + return llvm::createStringError( + "Invalid boolean value for option '%s': '%s'", + option_name.str().c_str(), + option_arg.empty() ? "<null>" : option_arg.str().c_str()); +} + char OptionArgParser::ToChar(llvm::StringRef s, char fail_value, bool *success_ptr) { if (success_ptr) @@ -93,8 +109,7 @@ Status OptionArgParser::ToFormat(const char *s, lldb::Format &format, *byte_size_ptr = 0; } - const bool partial_match_ok = true; - if (!FormatManager::GetFormatFromCString(s, partial_match_ok, format)) { + if (!FormatManager::GetFormatFromCString(s, format)) { StreamString error_strm; error_strm.Printf( "Invalid format character or name '%s'. Valid values are:\n", s); @@ -234,24 +249,68 @@ OptionArgParser::DoToAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, // Since the compiler can't handle things like "main + 12" we should try to // do this for now. The compiler doesn't like adding offsets to function // pointer types. + // Some languages also don't have a natural representation for register + // values (e.g. swift) so handle simple uses of them here as well. + // We use a regex to parse these forms, the regex handles: + // $reg_name + // $reg_name+offset + // symbol_name+offset + // + // The important matching elements in the regex below are: + // 1: The reg name if there's no +offset + // 3: The symbol/reg name if there is an offset + // 4: +/- + // 5: The offset value. static RegularExpression g_symbol_plus_offset_regex( - "^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$"); + "^(\\$[^ +-]+)|(([^ +-]+)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*)$"); llvm::SmallVector<llvm::StringRef, 4> matches; if (g_symbol_plus_offset_regex.Execute(sref, &matches)) { uint64_t offset = 0; - llvm::StringRef name = matches[1]; - llvm::StringRef sign = matches[2]; - llvm::StringRef str_offset = matches[3]; - if (!str_offset.getAsInteger(0, offset)) { + llvm::StringRef name; + if (!matches[1].empty()) + name = matches[1]; + else + name = matches[3]; + + llvm::StringRef sign = matches[4]; + llvm::StringRef str_offset = matches[5]; + + // Some languages don't have a natural type for register values, but it + // is still useful to look them up here: + std::optional<lldb::addr_t> register_value; + StackFrame *frame = exe_ctx->GetFramePtr(); + llvm::StringRef reg_name = name; + if (frame && reg_name.consume_front("$")) { + RegisterContextSP reg_ctx_sp = frame->GetRegisterContext(); + if (reg_ctx_sp) { + const RegisterInfo *reg_info = reg_ctx_sp->GetRegisterInfoByName(reg_name); + if (reg_info) { + RegisterValue reg_val; + bool success = reg_ctx_sp->ReadRegister(reg_info, reg_val); + if (success && reg_val.GetType() != RegisterValue::eTypeInvalid) { + register_value = reg_val.GetAsUInt64(0, &success); + if (!success) + register_value.reset(); + } + } + } + } + if (!str_offset.empty() && !str_offset.getAsInteger(0, offset)) { Status error; - addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error); + if (register_value) + addr = register_value.value(); + else + addr = ToAddress(exe_ctx, name, LLDB_INVALID_ADDRESS, &error); if (addr != LLDB_INVALID_ADDRESS) { if (sign[0] == '+') return addr + offset; return addr - offset; } - } + } else if (register_value) + // In the case of register values, someone might just want to get the + // value in a language whose expression parser doesn't support registers. + return register_value.value(); } if (error_ptr) diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp index 0e35a641361b..99644b3f423c 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/OptionGroupVariable.cpp @@ -50,6 +50,11 @@ static constexpr OptionDefinition g_variable_options[] = { "Specify a summary string to use to format the variable output."}, }; +static constexpr auto g_num_frame_options = 4; +static const auto g_variable_options_noframe = + llvm::ArrayRef<OptionDefinition>(g_variable_options) + .drop_front(g_num_frame_options); + static Status ValidateNamedSummary(const char *str, void *) { if (!str || !str[0]) return Status("must specify a valid named summary"); @@ -77,9 +82,9 @@ OptionGroupVariable::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) { Status error; - if (!include_frame_options) - option_idx += 3; - const int short_option = g_variable_options[option_idx].short_option; + llvm::ArrayRef<OptionDefinition> variable_options = + include_frame_options ? g_variable_options : g_variable_options_noframe; + const int short_option = variable_options[option_idx].short_option; switch (short_option) { case 'r': use_regex = true; @@ -128,16 +133,9 @@ void OptionGroupVariable::OptionParsingStarting( summary_string.Clear(); } -#define NUM_FRAME_OPTS 3 - llvm::ArrayRef<OptionDefinition> OptionGroupVariable::GetDefinitions() { - auto result = llvm::ArrayRef(g_variable_options); - // Show the "--no-args", "--no-locals" and "--show-globals" options if we are - // showing frame specific options - if (include_frame_options) - return result; - - // Skip the "--no-args", "--no-locals" and "--show-globals" options if we are - // not showing frame specific options (globals only) - return result.drop_front(NUM_FRAME_OPTS); + // Show the "--no-args", "--no-recognized-args", "--no-locals" and + // "--show-globals" options if we are showing frame specific options + return include_frame_options ? g_variable_options + : g_variable_options_noframe; } diff --git a/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp index 1999c63d11af..2e69c164e32a 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/OptionValueUInt64.cpp @@ -47,9 +47,16 @@ Status OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref, llvm::StringRef value_trimmed = value_ref.trim(); uint64_t value; if (llvm::to_integer(value_trimmed, value)) { - m_value_was_set = true; - m_current_value = value; - NotifyValueChanged(); + if (value >= m_min_value && value <= m_max_value) { + m_value_was_set = true; + m_current_value = value; + NotifyValueChanged(); + } else { + error.SetErrorStringWithFormat( + "%" PRIu64 " is out of range, valid values must be between %" PRIu64 + " and %" PRIu64 ".", + value, m_min_value, m_max_value); + } } else { error.SetErrorStringWithFormat("invalid uint64_t string value: '%s'", value_ref.str().c_str()); diff --git a/contrib/llvm-project/lldb/source/Interpreter/Options.cpp b/contrib/llvm-project/lldb/source/Interpreter/Options.cpp index 89fe69009d90..c5e75e0b9dce 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/Options.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/Options.cpp @@ -931,8 +931,7 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, Option *long_options = GetLongOptions(); if (long_options == nullptr) { - return llvm::make_error<llvm::StringError>("Invalid long options", - llvm::inconvertibleErrorCode()); + return llvm::createStringError("Invalid long options"); } std::string short_options = BuildShortOptions(long_options); @@ -957,8 +956,7 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, break; if (val == '?') { - return llvm::make_error<llvm::StringError>( - "Unknown or ambiguous option", llvm::inconvertibleErrorCode()); + return llvm::createStringError("Unknown or ambiguous option"); } if (val == 0) @@ -980,9 +978,8 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, // See if the option takes an argument, and see if one was supplied. if (long_options_index == -1) { - return llvm::make_error<llvm::StringError>( - llvm::formatv("Invalid option with value '{0}'.", char(val)).str(), - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + llvm::formatv("Invalid option with value '{0}'.", char(val)).str()); } StreamString option_str; @@ -995,11 +992,10 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, switch (has_arg) { case OptionParser::eRequiredArgument: if (OptionParser::GetOptionArgument() == nullptr) { - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( llvm::formatv("Option '{0}' is missing argument specifier.", option_str.GetString()) - .str(), - llvm::inconvertibleErrorCode()); + .str()); } [[fallthrough]]; case OptionParser::eOptionalArgument: @@ -1008,12 +1004,11 @@ llvm::Expected<Args> Options::ParseAlias(const Args &args, case OptionParser::eNoArgument: break; default: - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( llvm::formatv("error with options table; invalid value in has_arg " "field for option '{0}'.", char(val)) - .str(), - llvm::inconvertibleErrorCode()); + .str()); } // Find option in the argument list; also see if it was supposed to take an // argument and if one was supplied. Remove option (and argument, if @@ -1202,21 +1197,12 @@ OptionElementVector Options::ParseForCompletion(const Args &args, } break; case OptionParser::eOptionalArgument: - if (OptionParser::GetOptionArgument() != nullptr) { - option_element_vector.push_back(OptionArgElement( - opt_defs_index, - FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], - args), - FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], - args))); - } else { - option_element_vector.push_back(OptionArgElement( - opt_defs_index, - FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], - args), - FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], - args))); - } + option_element_vector.push_back(OptionArgElement( + opt_defs_index, + FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], + args), + FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], + args))); break; default: // The options table is messed up. Here we'll just continue @@ -1261,8 +1247,7 @@ llvm::Expected<Args> Options::Parse(const Args &args, Status error; Option *long_options = GetLongOptions(); if (long_options == nullptr) { - return llvm::make_error<llvm::StringError>("Invalid long options.", - llvm::inconvertibleErrorCode()); + return llvm::createStringError("Invalid long options."); } std::string short_options = BuildShortOptions(long_options); @@ -1322,9 +1307,8 @@ llvm::Expected<Args> Options::Parse(const Args &args, if (!platform_sp && require_validation) { // Caller requires validation but we cannot validate as we don't have // the mandatory platform against which to validate. - return llvm::make_error<llvm::StringError>( - "cannot validate options: no platform available", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "cannot validate options: no platform available"); } bool validation_failed = false; @@ -1365,3 +1349,16 @@ llvm::Expected<Args> Options::Parse(const Args &args, argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex()); return ReconstituteArgsAfterParsing(argv, args); } + +llvm::Error lldb_private::CreateOptionParsingError( + llvm::StringRef option_arg, const char short_option, + llvm::StringRef long_option, llvm::StringRef additional_context) { + std::string buffer; + llvm::raw_string_ostream stream(buffer); + stream << "Invalid value ('" << option_arg << "') for -" << short_option; + if (!long_option.empty()) + stream << " (" << long_option << ")"; + if (!additional_context.empty()) + stream << ": " << additional_context; + return llvm::createStringError(llvm::inconvertibleErrorCode(), buffer); +} diff --git a/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp b/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp index 8dd499ce819a..fa23964a52ff 100644 --- a/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/contrib/llvm-project/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -101,6 +101,22 @@ ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const { return Status(); } +Event * +ScriptInterpreter::GetOpaqueTypeFromSBEvent(const lldb::SBEvent &event) const { + return event.m_opaque_ptr; +} + +lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream( + const lldb::SBStream &stream) const { + if (stream.m_opaque_up) { + lldb::StreamSP s = std::make_shared<lldb_private::StreamString>(); + *s << reinterpret_cast<StreamString *>(stream.m_opaque_up.get())->m_packet; + return s; + } + + return nullptr; +} + std::optional<MemoryRegionInfo> ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( const lldb::SBMemoryRegionInfo &mem_region) const { diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 9baab3a10c1f..80921bcb199a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +#include "lldb/lldb-types.h" + #include "ABIAArch64.h" #ifdef LLDB_ENABLE_ALL #include "ABIMacOSX_arm64.h" @@ -18,6 +20,8 @@ #include <bitset> #include <optional> +using namespace lldb; + LLDB_PLUGIN_DEFINE(ABIAArch64) void ABIAArch64::Initialize() { @@ -35,14 +39,35 @@ void ABIAArch64::Terminate() { } lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) { - if (lldb::ProcessSP process_sp = GetProcessSP()) - return FixAddress(pc, process_sp->GetCodeAddressMask()); + if (lldb::ProcessSP process_sp = GetProcessSP()) { + // b55 is the highest bit outside TBI (if it's enabled), use + // it to determine if the high bits are set to 0 or 1. + const addr_t pac_sign_extension = 0x0080000000000000ULL; + addr_t mask = process_sp->GetCodeAddressMask(); + // Test if the high memory mask has been overriden separately + if (pc & pac_sign_extension && + process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK) + mask = process_sp->GetHighmemCodeAddressMask(); + + if (mask != LLDB_INVALID_ADDRESS_MASK) + return FixAddress(pc, mask); + } return pc; } lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) { - if (lldb::ProcessSP process_sp = GetProcessSP()) - return FixAddress(pc, process_sp->GetDataAddressMask()); + if (lldb::ProcessSP process_sp = GetProcessSP()) { + // b55 is the highest bit outside TBI (if it's enabled), use + // it to determine if the high bits are set to 0 or 1. + const addr_t pac_sign_extension = 0x0080000000000000ULL; + addr_t mask = process_sp->GetDataAddressMask(); + // Test if the high memory mask has been overriden separately + if (pc & pac_sign_extension && + process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK) + mask = process_sp->GetHighmemDataAddressMask(); + if (mask != LLDB_INVALID_ADDRESS_MASK) + return FixAddress(pc, mask); + } return pc; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index f4ef9b4fc824..045d6a405e69 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -814,11 +814,11 @@ addr_t ABIMacOSX_arm64::FixCodeAddress(addr_t pc) { mask = process_sp->GetCodeAddressMask(); if (pc & pac_sign_extension) { addr_t highmem_mask = process_sp->GetHighmemCodeAddressMask(); - if (highmem_mask) + if (highmem_mask != LLDB_INVALID_ADDRESS_MASK) mask = highmem_mask; } } - if (mask == 0) + if (mask == LLDB_INVALID_ADDRESS_MASK) mask = tbi_mask; return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); @@ -833,11 +833,11 @@ addr_t ABIMacOSX_arm64::FixDataAddress(addr_t pc) { mask = process_sp->GetDataAddressMask(); if (pc & pac_sign_extension) { addr_t highmem_mask = process_sp->GetHighmemDataAddressMask(); - if (highmem_mask) + if (highmem_mask != LLDB_INVALID_ADDRESS_MASK) mask = highmem_mask; } } - if (mask == 0) + if (mask == LLDB_INVALID_ADDRESS_MASK) mask = tbi_mask; return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index bf3c5ddd5889..cd7481f88efd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -775,6 +775,8 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( } lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) { + if (mask == LLDB_INVALID_ADDRESS_MASK) + return pc; lldb::addr_t pac_sign_extension = 0x0080000000000000ULL; return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); } @@ -782,12 +784,12 @@ lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) { // Reads code or data address mask for the current Linux process. static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp, llvm::StringRef reg_name) { - // 0 means there isn't a mask or it has not been read yet. - // We do not return the top byte mask unless thread_sp is valid. - // This prevents calls to this function before the thread is setup locking - // in the value to just the top byte mask, in cases where pointer - // authentication might also be active. - uint64_t address_mask = 0; + // LLDB_INVALID_ADDRESS_MASK means there isn't a mask or it has not been read + // yet. We do not return the top byte mask unless thread_sp is valid. This + // prevents calls to this function before the thread is setup locking in the + // value to just the top byte mask, in cases where pointer authentication + // might also be active. + uint64_t address_mask = LLDB_INVALID_ADDRESS_MASK; lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); if (thread_sp) { // Linux configures user-space virtual addresses with top byte ignored. @@ -814,11 +816,20 @@ static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp, lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) { if (lldb::ProcessSP process_sp = GetProcessSP()) { if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() && - !process_sp->GetCodeAddressMask()) + process_sp->GetCodeAddressMask() == LLDB_INVALID_ADDRESS_MASK) process_sp->SetCodeAddressMask( ReadLinuxProcessAddressMask(process_sp, "code_mask")); - return FixAddress(pc, process_sp->GetCodeAddressMask()); + // b55 is the highest bit outside TBI (if it's enabled), use + // it to determine if the high bits are set to 0 or 1. + const addr_t pac_sign_extension = 0x0080000000000000ULL; + addr_t mask = process_sp->GetCodeAddressMask(); + // Test if the high memory mask has been overriden separately + if (pc & pac_sign_extension && + process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK) + mask = process_sp->GetHighmemCodeAddressMask(); + + return FixAddress(pc, mask); } return pc; } @@ -826,11 +837,20 @@ lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) { lldb::addr_t ABISysV_arm64::FixDataAddress(lldb::addr_t pc) { if (lldb::ProcessSP process_sp = GetProcessSP()) { if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() && - !process_sp->GetDataAddressMask()) + process_sp->GetDataAddressMask() == LLDB_INVALID_ADDRESS_MASK) process_sp->SetDataAddressMask( ReadLinuxProcessAddressMask(process_sp, "data_mask")); - return FixAddress(pc, process_sp->GetDataAddressMask()); + // b55 is the highest bit outside TBI (if it's enabled), use + // it to determine if the high bits are set to 0 or 1. + const addr_t pac_sign_extension = 0x0080000000000000ULL; + addr_t mask = process_sp->GetDataAddressMask(); + // Test if the high memory mask has been overriden separately + if (pc & pac_sign_extension && + process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK) + mask = process_sp->GetHighmemDataAddressMask(); + + return FixAddress(pc, mask); } return pc; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 656f07437095..eac058701313 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -501,14 +501,12 @@ public: CompilerType &type) { RegisterContext *reg_ctx = thread.GetRegisterContext().get(); if (!reg_ctx) - return llvm::make_error<llvm::StringError>( - LOG_PREFIX "Failed to get RegisterContext", - llvm::inconvertibleErrorCode()); + return llvm::createStringError(LOG_PREFIX + "Failed to get RegisterContext"); ProcessSP process_sp = thread.GetProcess(); if (!process_sp) - return llvm::make_error<llvm::StringError>( - LOG_PREFIX "GetProcess() failed", llvm::inconvertibleErrorCode()); + return llvm::createStringError(LOG_PREFIX "GetProcess() failed"); return ReturnValueExtractor(thread, type, reg_ctx, process_sp); } @@ -768,7 +766,12 @@ private: // get number of children const bool omit_empty_base_classes = true; - uint32_t n = m_type.GetNumChildren(omit_empty_base_classes, nullptr); + auto n_or_err = m_type.GetNumChildren(omit_empty_base_classes, nullptr); + if (!n_or_err) { + LLDB_LOG_ERROR(m_log, n_or_err.takeError(), LOG_PREFIX "{0}"); + return {}; + } + uint32_t n = *n_or_err; if (!n) { LLDB_LOG(m_log, LOG_PREFIX "No children found in struct"); return {}; @@ -831,7 +834,7 @@ private: for (uint32_t i = 0; i < n; i++) { std::string name; uint32_t size; - GetChildType(i, name, size); + (void)GetChildType(i, name, size); // NOTE: the offset returned by GetChildCompilerTypeAtIndex() // can't be used because it never considers alignment bytes // between struct fields. @@ -898,7 +901,8 @@ private: } // get child - CompilerType GetChildType(uint32_t i, std::string &name, uint32_t &size) { + llvm::Expected<CompilerType> GetChildType(uint32_t i, std::string &name, + uint32_t &size) { // GetChild constant inputs const bool transparent_pointers = false; const bool omit_empty_base_classes = true; diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp index 6395f5bb5bd9..35d4f0521bf1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp @@ -13,6 +13,7 @@ #include "llvm/IR/DerivedTypes.h" +#include "Utility/RISCV_DWARF_Registers.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" @@ -643,9 +644,9 @@ bool ABISysV_riscv::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind(eRegisterKindDWARF); - uint32_t pc_reg_num = LLDB_REGNUM_GENERIC_PC; - uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP; - uint32_t ra_reg_num = LLDB_REGNUM_GENERIC_RA; + uint32_t pc_reg_num = riscv_dwarf::dwarf_gpr_pc; + uint32_t sp_reg_num = riscv_dwarf::dwarf_gpr_sp; + uint32_t ra_reg_num = riscv_dwarf::dwarf_gpr_ra; UnwindPlan::RowSP row(new UnwindPlan::Row); diff --git a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h index a9c2ed9c2f14..2fab0fd61ea3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h @@ -1,4 +1,4 @@ -//===-- ABIWindows_x86_64.h ----------------------------------------*- C++ -*-===// +//===-- ABIWindows_x86_64.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. diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h index 9513a10b5965..cedd4127afcb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -1,4 +1,4 @@ -//===-- ArchitectureMips.h ---------------------------------------*- C++ -*-===// +//===-- ArchitectureMips.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. diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp index 6d2e17d4eac6..e504e6cbf692 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp @@ -410,8 +410,7 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule( // Find the slide address addr_t fixed_slide = LLDB_INVALID_ADDRESS; - if (ObjectFileELF *memory_objfile_elf = - llvm::dyn_cast<ObjectFileELF>(memory_object_file)) { + if (llvm::dyn_cast<ObjectFileELF>(memory_object_file)) { addr_t load_address = memory_object_file->GetBaseAddress().GetFileAddress(); if (load_address != LLDB_INVALID_ADDRESS && diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp index 9baf86da4dc7..51e4b3e6728f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -506,6 +506,19 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, Target &target = thread.GetProcess()->GetTarget(); const ModuleList &images = target.GetImages(); + llvm::StringRef target_name = sym_name.GetStringRef(); + // On AArch64, the trampoline name has a prefix (__AArch64ADRPThunk_ or + // __AArch64AbsLongThunk_) added to the function name. If we detect a + // trampoline with the prefix, we need to remove the prefix to find the + // function symbol. + if (target_name.consume_front("__AArch64ADRPThunk_") || + target_name.consume_front("__AArch64AbsLongThunk_")) { + // An empty target name can happen for trampolines generated for + // section-referencing relocations. + if (!target_name.empty()) { + sym_name = ConstString(target_name); + } + } images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols); if (!target_symbols.GetSize()) return thread_plan_sp; @@ -571,10 +584,17 @@ ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { FileSpec file(info.GetName().GetCString()); ModuleSpec module_spec(file, target.GetArchitecture()); - if (ModuleSP module_sp = target.GetOrCreateModule(module_spec, - true /* notify */)) { + // Don't notify that module is added here because its loading section + // addresses are not updated yet. We manually notify it below. + if (ModuleSP module_sp = + target.GetOrCreateModule(module_spec, /*notify=*/false)) { UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base, false); + // Manually notify that dynamic linker is loaded after updating load section + // addersses so that breakpoints can be resolved. + ModuleList module_list; + module_list.Append(module_sp); + target.ModulesDidLoad(module_list); m_interpreter_module = module_sp; return module_sp; } diff --git a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index a39aa2280ab8..545998123dda 100644 --- a/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -84,51 +84,43 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { // Disable JIT for static dynamic loader targets m_process->SetCanJIT(false); + Target &target = m_process->GetTarget(); for (ModuleSP module_sp : module_list.Modules()) { if (module_sp) { bool changed = false; + bool no_load_addresses = true; + // If this module has a section with a load address set in + // the target, assume all necessary work is already done. There + // may be sections without a load address set intentionally + // and we don't want to mutate that. + // For a module with no load addresses set, set the load addresses + // to slide == 0, the same as the file addresses, in the target. ObjectFile *image_object_file = module_sp->GetObjectFile(); if (image_object_file) { SectionList *section_list = image_object_file->GetSectionList(); if (section_list) { - // All sections listed in the dyld image info structure will all - // either be fixed up already, or they will all be off by a single - // slide amount that is determined by finding the first segment that - // is at file offset zero which also has bytes (a file size that is - // greater than zero) in the object file. - - // Determine the slide amount (if any) const size_t num_sections = section_list->GetSize(); - size_t sect_idx = 0; - for (sect_idx = 0; sect_idx < num_sections; ++sect_idx) { - // Iterate through the object file sections to find the first - // section that starts of file offset zero and that has bytes in - // the file... + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (section_sp) { - // If this section already has a load address set in the target, - // don't re-set it to the file address. Something may have - // set it to a more correct value already. - if (m_process->GetTarget() - .GetSectionLoadList() - .GetSectionLoadAddress(section_sp) != - LLDB_INVALID_ADDRESS) { - continue; + if (target.GetSectionLoadList().GetSectionLoadAddress( + section_sp) != LLDB_INVALID_ADDRESS) { + no_load_addresses = false; + break; } - if (m_process->GetTarget().SetSectionLoadAddress( - section_sp, section_sp->GetFileAddress())) - changed = true; } } } } + if (no_load_addresses) + module_sp->SetLoadAddress(target, 0, true /*value_is_offset*/, changed); if (changed) loaded_module_list.AppendIfNeeded(module_sp); } } - m_process->GetTarget().ModulesDidLoad(loaded_module_list); + target.ModulesDidLoad(loaded_module_list); } ThreadPlanSP diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index 95e8a600f838..da2b1a15f746 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -9,13 +9,19 @@ #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_ASTUTILS_H -#include "clang/Basic/Module.h" +#include "clang/Basic/ASTSourceDescriptor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaConsumer.h" #include <optional> +namespace clang { + +class Module; + +} // namespace clang + namespace lldb_private { /// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take @@ -30,7 +36,7 @@ public: ~ExternalASTSourceWrapper() override; - clang::Decl *GetExternalDecl(uint32_t ID) override { + clang::Decl *GetExternalDecl(clang::GlobalDeclID ID) override { return m_Source->GetExternalDecl(ID); } @@ -56,7 +62,7 @@ public: return m_Source->GetExternalCXXBaseSpecifiers(Offset); } - void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override { + void updateOutOfDateIdentifier(const clang::IdentifierInfo &II) override { m_Source->updateOutOfDateIdentifier(II); } @@ -266,7 +272,7 @@ public: // ExternalASTSource. //===--------------------------------------------------------------------===// - clang::Decl *GetExternalDecl(uint32_t ID) override { + clang::Decl *GetExternalDecl(clang::GlobalDeclID ID) override { for (size_t i = 0; i < Sources.size(); ++i) if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID)) return Result; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 62a30c14912b..44071d1ea71c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -10,9 +10,11 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/RecordLayout.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" @@ -26,6 +28,7 @@ #include <memory> #include <optional> +#include <type_traits> using namespace lldb_private; using namespace clang; @@ -310,8 +313,8 @@ CompilerType ClangASTImporter::DeportType(TypeSystemClang &dst, return {}; LLDB_LOG(log, - " [ClangASTImporter] DeportType called on ({0}Type*){1} " - "from (ASTContext*){2} to (ASTContext*){3}", + " [ClangASTImporter] DeportType called on ({0}Type*){1:x} " + "from (ASTContext*){2:x} to (ASTContext*){3:x}", src_type.GetTypeName(), src_type.GetOpaqueQualType(), &src_ctxt->getASTContext(), &dst.getASTContext()); @@ -331,8 +334,8 @@ clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx = &decl->getASTContext(); LLDB_LOG(log, - " [ClangASTImporter] DeportDecl called on ({0}Decl*){1} from " - "(ASTContext*){2} to (ASTContext*){3}", + " [ClangASTImporter] DeportDecl called on ({0}Decl*){1:x} from " + "(ASTContext*){2:x} to (ASTContext*){3:x}", decl->getDeclKindName(), decl, src_ctx, dst_ctx); DeclContextOverride decl_context_override; @@ -349,8 +352,8 @@ clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, return nullptr; LLDB_LOG(log, - " [ClangASTImporter] DeportDecl deported ({0}Decl*){1} to " - "({2}Decl*){3}", + " [ClangASTImporter] DeportDecl deported ({0}Decl*){1:x} to " + "({2}Decl*){3:x}", decl->getDeclKindName(), decl, result->getDeclKindName(), result); return result; @@ -517,6 +520,236 @@ bool ClangASTImporter::CompleteType(const CompilerType &compiler_type) { return false; } +/// Copy layout information from \ref source_map to the \ref destination_map. +/// +/// In the process of copying over layout info, we may need to import +/// decls from the \ref source_map. This function will use the supplied +/// \ref importer to import the necessary decls into \ref dest_ctx. +/// +/// \param[in,out] dest_ctx Destination ASTContext into which we import +/// decls from the \ref source_map. +/// \param[out] destination_map A map from decls in \ref dest_ctx to an +/// integral offest, which will be copies +/// of the decl/offest pairs in \ref source_map +/// if successful. +/// \param[in] source_map A map from decls to integral offests. These will +/// be copied into \ref destination_map. +/// \param[in,out] importer Used to import decls into \ref dest_ctx. +/// +/// \returns On success, will return 'true' and the offsets in \ref +/// destination_map +/// are usable copies of \ref source_map. +template <class D, class O> +static bool ImportOffsetMap(clang::ASTContext *dest_ctx, + llvm::DenseMap<const D *, O> &destination_map, + llvm::DenseMap<const D *, O> &source_map, + ClangASTImporter &importer) { + // When importing fields into a new record, clang has a hard requirement that + // fields be imported in field offset order. Since they are stored in a + // DenseMap with a pointer as the key type, this means we cannot simply + // iterate over the map, as the order will be non-deterministic. Instead we + // have to sort by the offset and then insert in sorted order. + typedef llvm::DenseMap<const D *, O> MapType; + typedef typename MapType::value_type PairType; + std::vector<PairType> sorted_items; + sorted_items.reserve(source_map.size()); + sorted_items.assign(source_map.begin(), source_map.end()); + llvm::sort(sorted_items, llvm::less_second()); + + for (const auto &item : sorted_items) { + DeclFromUser<D> user_decl(const_cast<D *>(item.first)); + DeclFromParser<D> parser_decl(user_decl.Import(dest_ctx, importer)); + if (parser_decl.IsInvalid()) + return false; + destination_map.insert( + std::pair<const D *, O>(parser_decl.decl, item.second)); + } + + return true; +} + +/// Given a CXXRecordDecl, will calculate and populate \ref base_offsets +/// with the integral offsets of any of its (possibly virtual) base classes. +/// +/// \param[in] record_layout ASTRecordLayout of \ref record. +/// \param[in] record The record that we're calculating the base layouts of. +/// \param[out] base_offsets Map of base-class decl to integral offset which +/// this function will fill in. +/// +/// \returns On success, will return 'true' and the offsets in \ref base_offsets +/// are usable. +template <bool IsVirtual> +bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, + DeclFromUser<const CXXRecordDecl> &record, + llvm::DenseMap<const clang::CXXRecordDecl *, + clang::CharUnits> &base_offsets) { + for (CXXRecordDecl::base_class_const_iterator + bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), + be = (IsVirtual ? record->vbases_end() : record->bases_end()); + bi != be; ++bi) { + if (!IsVirtual && bi->isVirtual()) + continue; + + const clang::Type *origin_base_type = bi->getType().getTypePtr(); + const clang::RecordType *origin_base_record_type = + origin_base_type->getAs<RecordType>(); + + if (!origin_base_record_type) + return false; + + DeclFromUser<RecordDecl> origin_base_record( + origin_base_record_type->getDecl()); + + if (origin_base_record.IsInvalid()) + return false; + + DeclFromUser<CXXRecordDecl> origin_base_cxx_record( + DynCast<CXXRecordDecl>(origin_base_record)); + + if (origin_base_cxx_record.IsInvalid()) + return false; + + CharUnits base_offset; + + if (IsVirtual) + base_offset = + record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); + else + base_offset = + record_layout.getBaseClassOffset(origin_base_cxx_record.decl); + + base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>( + origin_base_cxx_record.decl, base_offset)); + } + + return true; +} + +bool ClangASTImporter::importRecordLayoutFromOrigin( + const RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets) { + + Log *log = GetLog(LLDBLog::Expressions); + + clang::ASTContext &dest_ctx = record->getASTContext(); + LLDB_LOG(log, + "LayoutRecordType on (ASTContext*){0:x} '{1}' for (RecordDecl*)" + "{2:x} [name = '{3}']", + &dest_ctx, + TypeSystemClang::GetASTContext(&dest_ctx)->getDisplayName(), record, + record->getName()); + + DeclFromParser<const RecordDecl> parser_record(record); + DeclFromUser<const RecordDecl> origin_record(parser_record.GetOrigin(*this)); + + if (origin_record.IsInvalid()) + return false; + + std::remove_reference_t<decltype(field_offsets)> origin_field_offsets; + std::remove_reference_t<decltype(base_offsets)> origin_base_offsets; + std::remove_reference_t<decltype(vbase_offsets)> origin_virtual_base_offsets; + + TypeSystemClang::GetCompleteDecl( + &origin_record->getASTContext(), + const_cast<RecordDecl *>(origin_record.decl)); + + clang::RecordDecl *definition = origin_record.decl->getDefinition(); + if (!definition || !definition->isCompleteDefinition()) + return false; + + const ASTRecordLayout &record_layout( + origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); + + int field_idx = 0, field_count = record_layout.getFieldCount(); + + for (RecordDecl::field_iterator fi = origin_record->field_begin(), + fe = origin_record->field_end(); + fi != fe; ++fi) { + if (field_idx >= field_count) + return false; // Layout didn't go well. Bail out. + + uint64_t field_offset = record_layout.getFieldOffset(field_idx); + + origin_field_offsets.insert( + std::pair<const FieldDecl *, uint64_t>(*fi, field_offset)); + + field_idx++; + } + + DeclFromUser<const CXXRecordDecl> origin_cxx_record( + DynCast<const CXXRecordDecl>(origin_record)); + + if (origin_cxx_record.IsValid()) { + if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, + origin_base_offsets) || + !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, + origin_virtual_base_offsets)) + return false; + } + + if (!ImportOffsetMap(&dest_ctx, field_offsets, origin_field_offsets, *this) || + !ImportOffsetMap(&dest_ctx, base_offsets, origin_base_offsets, *this) || + !ImportOffsetMap(&dest_ctx, vbase_offsets, origin_virtual_base_offsets, + *this)) + return false; + + size = record_layout.getSize().getQuantity() * dest_ctx.getCharWidth(); + alignment = + record_layout.getAlignment().getQuantity() * dest_ctx.getCharWidth(); + + if (log) { + LLDB_LOG(log, "LRT returned:"); + LLDB_LOG(log, "LRT Original = (RecordDecl*){0:x}", + static_cast<const void *>(origin_record.decl)); + LLDB_LOG(log, "LRT Size = {0}", size); + LLDB_LOG(log, "LRT Alignment = {0}", alignment); + LLDB_LOG(log, "LRT Fields:"); + for (RecordDecl::field_iterator fi = record->field_begin(), + fe = record->field_end(); + fi != fe; ++fi) { + LLDB_LOG( + log, + "LRT (FieldDecl*){0:x}, Name = '{1}', Type = '{2}', Offset = " + "{3} bits", + *fi, fi->getName(), fi->getType().getAsString(), field_offsets[*fi]); + } + DeclFromParser<const CXXRecordDecl> parser_cxx_record = + DynCast<const CXXRecordDecl>(parser_record); + if (parser_cxx_record.IsValid()) { + LLDB_LOG(log, "LRT Bases:"); + for (CXXRecordDecl::base_class_const_iterator + bi = parser_cxx_record->bases_begin(), + be = parser_cxx_record->bases_end(); + bi != be; ++bi) { + bool is_virtual = bi->isVirtual(); + + QualType base_type = bi->getType(); + const RecordType *base_record_type = base_type->getAs<RecordType>(); + DeclFromParser<RecordDecl> base_record(base_record_type->getDecl()); + DeclFromParser<CXXRecordDecl> base_cxx_record = + DynCast<CXXRecordDecl>(base_record); + + LLDB_LOG(log, + "LRT {0}(CXXRecordDecl*){1:x}, Name = '{2}', Offset = " + "{3} chars", + (is_virtual ? "Virtual " : ""), base_cxx_record.decl, + base_cxx_record.decl->getName(), + (is_virtual + ? vbase_offsets[base_cxx_record.decl].getQuantity() + : base_offsets[base_cxx_record.decl].getQuantity())); + } + } else { + LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); + } + } + + return true; +} + bool ClangASTImporter::LayoutRecordType( const clang::RecordDecl *record_decl, uint64_t &bit_size, uint64_t &alignment, @@ -527,7 +760,6 @@ bool ClangASTImporter::LayoutRecordType( &vbase_offsets) { RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find(record_decl); - bool success = false; base_offsets.clear(); vbase_offsets.clear(); if (pos != m_record_decl_to_layout_map.end()) { @@ -537,13 +769,23 @@ bool ClangASTImporter::LayoutRecordType( base_offsets.swap(pos->second.base_offsets); vbase_offsets.swap(pos->second.vbase_offsets); m_record_decl_to_layout_map.erase(pos); - success = true; - } else { - bit_size = 0; - alignment = 0; - field_offsets.clear(); + return true; } - return success; + + // It's possible that we calculated the layout in a different + // ClangASTImporter instance. Try to import such layout if + // our decl has an origin. + if (auto origin = GetDeclOrigin(record_decl); origin.Valid()) + if (importRecordLayoutFromOrigin(record_decl, bit_size, alignment, + field_offsets, base_offsets, + vbase_offsets)) + return true; + + bit_size = 0; + alignment = 0; + field_offsets.clear(); + + return false; } void ClangASTImporter::SetRecordLayout(clang::RecordDecl *decl, @@ -783,7 +1025,7 @@ void ClangASTImporter::ForgetDestination(clang::ASTContext *dst_ast) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, - " [ClangASTImporter] Forgetting destination (ASTContext*){0}", + " [ClangASTImporter] Forgetting destination (ASTContext*){0:x}", dst_ast); m_metadata_map.erase(dst_ast); @@ -797,7 +1039,7 @@ void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, LLDB_LOG(log, " [ClangASTImporter] Forgetting source->dest " - "(ASTContext*){0}->(ASTContext*){1}", + "(ASTContext*){0:x}->(ASTContext*){1:x}", src_ast, dst_ast); if (!md) @@ -922,9 +1164,10 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( from_named_decl->printName(name_stream); name_stream.flush(); } - LLDB_LOG(log_ast, "==== [ClangASTImporter][TUDecl: {0}] Imported " - "({1}Decl*){2}, named {3} (from " - "(Decl*){4})", + LLDB_LOG(log_ast, + "==== [ClangASTImporter][TUDecl: {0:x}] Imported " + "({1}Decl*){2:x}, named {3} (from " + "(Decl*){4:x})", static_cast<void *>(to->getTranslationUnitDecl()), from->getDeclKindName(), static_cast<void *>(to), name_string, static_cast<void *>(from)); @@ -1052,14 +1295,15 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, from_named_decl->printName(name_stream); name_stream.flush(); - LLDB_LOG(log, - " [ClangASTImporter] Imported ({0}Decl*){1}, named {2} (from " - "(Decl*){3}), metadata {4}", - from->getDeclKindName(), to, name_string, from, user_id); + LLDB_LOG( + log, + " [ClangASTImporter] Imported ({0}Decl*){1:x}, named {2} (from " + "(Decl*){3:x}), metadata {4}", + from->getDeclKindName(), to, name_string, from, user_id); } else { LLDB_LOG(log, - " [ClangASTImporter] Imported ({0}Decl*){1} (from " - "(Decl*){2}), metadata {3}", + " [ClangASTImporter] Imported ({0}Decl*){1:x} (from " + "(Decl*){2:x}), metadata {3}", from->getDeclKindName(), to, from, user_id); } } @@ -1079,8 +1323,8 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, LLDB_LOG(log, " [ClangASTImporter] Propagated origin " - "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " - "(ASTContext*){3}", + "(Decl*){0:x}/(ASTContext*){1:x} from (ASTContext*){2:x} to " + "(ASTContext*){3:x}", origin.decl, origin.ctx, &from->getASTContext(), &to->getASTContext()); } @@ -1093,7 +1337,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, LLDB_LOG(log, " [ClangASTImporter] Decl has no origin information in " - "(ASTContext*){0}", + "(ASTContext*){0:x}", &from->getASTContext()); } @@ -1114,7 +1358,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, LLDB_LOG(log, " [ClangASTImporter] Sourced origin " - "(Decl*){0}/(ASTContext*){1} into (ASTContext*){2}", + "(Decl*){0:x}/(ASTContext*){1:x} into (ASTContext*){2:x}", from, m_source_ctx, &to->getASTContext()); } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index e565a96b217f..bc962e544d2f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -14,6 +14,7 @@ #include <set> #include <vector> +#include "clang/AST/ASTContext.h" #include "clang/AST/ASTImporter.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" @@ -127,6 +128,27 @@ public: llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets); + /// If \ref record has a valid origin, this function copies that + /// origin's layout into this ClangASTImporter instance. + /// + /// \param[in] record The decl whose layout we're calculating. + /// \param[out] size Size of \ref record in bytes. + /// \param[out] alignment Alignment of \ref record in bytes. + /// \param[out] field_offsets Offsets of fields of \ref record. + /// \param[out] base_offsets Offsets of base classes of \ref record. + /// \param[out] vbase_offsets Offsets of virtual base classes of \ref record. + /// + /// \returns Returns 'false' if no valid origin was found for \ref record or + /// this function failed to import the layout from the origin. Otherwise, + /// returns 'true' and the offsets/size/alignment are valid for use. + bool importRecordLayoutFromOrigin( + const clang::RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &vbase_offsets); + /// Returns true iff the given type was copied from another TypeSystemClang /// and the original type in this other TypeSystemClang might contain /// additional information (e.g., the definition of a 'class' type) that could @@ -456,6 +478,58 @@ public: RecordDeclToLayoutMap m_record_decl_to_layout_map; }; +template <class D> class TaggedASTDecl { +public: + TaggedASTDecl() : decl(nullptr) {} + TaggedASTDecl(D *_decl) : decl(_decl) {} + bool IsValid() const { return (decl != nullptr); } + bool IsInvalid() const { return !IsValid(); } + D *operator->() const { return decl; } + D *decl; +}; + +template <class D2, template <class D> class TD, class D1> +TD<D2> DynCast(TD<D1> source) { + return TD<D2>(llvm::dyn_cast<D2>(source.decl)); +} + +template <class D = clang::Decl> class DeclFromParser; +template <class D = clang::Decl> class DeclFromUser; + +template <class D> class DeclFromParser : public TaggedASTDecl<D> { +public: + DeclFromParser() : TaggedASTDecl<D>() {} + DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} + + DeclFromUser<D> GetOrigin(ClangASTImporter &importer); +}; + +template <class D> class DeclFromUser : public TaggedASTDecl<D> { +public: + DeclFromUser() : TaggedASTDecl<D>() {} + DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} + + DeclFromParser<D> Import(clang::ASTContext *dest_ctx, + ClangASTImporter &importer); +}; + +template <class D> +DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTImporter &importer) { + ClangASTImporter::DeclOrigin origin = importer.GetDeclOrigin(this->decl); + if (!origin.Valid()) + return DeclFromUser<D>(); + return DeclFromUser<D>(llvm::dyn_cast<D>(origin.decl)); +} + +template <class D> +DeclFromParser<D> DeclFromUser<D>::Import(clang::ASTContext *dest_ctx, + ClangASTImporter &importer) { + DeclFromParser<> parser_generic_decl(importer.CopyDecl(dest_ctx, this->decl)); + if (parser_generic_decl.IsInvalid()) + return DeclFromParser<D>(); + return DeclFromParser<D>(llvm::dyn_cast<D>(parser_generic_decl.decl)); +} + } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 79dd306f7627..1fdd272dcbec 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -21,7 +21,6 @@ #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/RecordLayout.h" #include "clang/Basic/SourceManager.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" @@ -194,7 +193,7 @@ TagDecl *ClangASTSource::FindCompleteType(const TagDecl *decl) { if (!namespace_map) return nullptr; - LLDB_LOGV(log, " CTD Inspecting namespace map{0} ({1} entries)", + LLDB_LOGV(log, " CTD Inspecting namespace map{0:x} ({1} entries)", namespace_map.get(), namespace_map->size()); for (const ClangASTImporter::NamespaceMapItem &item : *namespace_map) { @@ -266,7 +265,7 @@ void ClangASTSource::CompleteType(TagDecl *tag_decl) { if (log) { LLDB_LOG(log, " CompleteTagDecl on (ASTContext*){0} Completing " - "(TagDecl*){1} named {2}", + "(TagDecl*){1:x} named {2}", m_clang_ast_context->getDisplayName(), tag_decl, tag_decl->getName()); @@ -293,7 +292,7 @@ void ClangASTSource::CompleteType(clang::ObjCInterfaceDecl *interface_decl) { Log *log = GetLog(LLDBLog::Expressions); LLDB_LOG(log, - " [CompleteObjCInterfaceDecl] on (ASTContext*){0} '{1}' " + " [CompleteObjCInterfaceDecl] on (ASTContext*){0:x} '{1}' " "Completing an ObjCInterfaceDecl named {1}", m_ast_context, m_clang_ast_context->getDisplayName(), interface_decl->getName()); @@ -386,7 +385,7 @@ void ClangASTSource::FindExternalLexicalDecls( if (log) { if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl)) LLDB_LOG(log, - "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in " "'{2}' ({3}Decl*){4}", m_ast_context, m_clang_ast_context->getDisplayName(), context_named_decl->getNameAsString().c_str(), @@ -394,14 +393,14 @@ void ClangASTSource::FindExternalLexicalDecls( static_cast<const void *>(context_decl)); else if (context_decl) LLDB_LOG(log, - "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in " + "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in " "({2}Decl*){3}", m_ast_context, m_clang_ast_context->getDisplayName(), context_decl->getDeclKindName(), static_cast<const void *>(context_decl)); else LLDB_LOG(log, - "FindExternalLexicalDecls on (ASTContext*){0} '{1}' in a " + "FindExternalLexicalDecls on (ASTContext*){0:x} '{1}' in a " "NULL context", m_ast_context, m_clang_ast_context->getDisplayName()); } @@ -411,7 +410,7 @@ void ClangASTSource::FindExternalLexicalDecls( if (!original.Valid()) return; - LLDB_LOG(log, " FELD Original decl {0} (Decl*){1:x}:\n{2}", + LLDB_LOG(log, " FELD Original decl (ASTContext*){0:x} (Decl*){1:x}:\n{2}", static_cast<void *>(original.ctx), static_cast<void *>(original.decl), ClangUtil::DumpDecl(original.decl)); @@ -509,19 +508,19 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { if (!context.m_decl_context) LLDB_LOG(log, "ClangASTSource::FindExternalVisibleDecls on " - "(ASTContext*){0} '{1}' for '{2}' in a NULL DeclContext", + "(ASTContext*){0:x} '{1}' for '{2}' in a NULL DeclContext", m_ast_context, m_clang_ast_context->getDisplayName(), name); else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context)) LLDB_LOG(log, "ClangASTSource::FindExternalVisibleDecls on " - "(ASTContext*){0} '{1}' for '{2}' in '{3}'", + "(ASTContext*){0:x} '{1}' for '{2}' in '{3}'", m_ast_context, m_clang_ast_context->getDisplayName(), name, context_named_decl->getName()); else LLDB_LOG(log, "ClangASTSource::FindExternalVisibleDecls on " - "(ASTContext*){0} '{1}' for '{2}' in a '{3}'", + "(ASTContext*){0:x} '{1}' for '{2}' in a '{3}'", m_ast_context, m_clang_ast_context->getDisplayName(), name, context.m_decl_context->getDeclKindName()); } @@ -543,7 +542,7 @@ void ClangASTSource::FindExternalVisibleDecls(NameSearchContext &context) { if (!context.m_namespace_map->empty()) { if (log && log->GetVerbose()) - LLDB_LOG(log, " CAS::FEVD Registering namespace map {0} ({1} entries)", + LLDB_LOG(log, " CAS::FEVD Registering namespace map {0:x} ({1} entries)", context.m_namespace_map.get(), context.m_namespace_map->size()); NamespaceDecl *clang_namespace_decl = @@ -638,7 +637,7 @@ void ClangASTSource::FindExternalVisibleDecls( FindDeclInModules(context, name); } - if (!context.m_found_type) { + if (!context.m_found_type && m_ast_context->getLangOpts().ObjC) { FindDeclInObjCRuntime(context, name); } } @@ -705,56 +704,6 @@ void ClangASTSource::FillNamespaceMap( } } -template <class D> class TaggedASTDecl { -public: - TaggedASTDecl() : decl(nullptr) {} - TaggedASTDecl(D *_decl) : decl(_decl) {} - bool IsValid() const { return (decl != nullptr); } - bool IsInvalid() const { return !IsValid(); } - D *operator->() const { return decl; } - D *decl; -}; - -template <class D2, template <class D> class TD, class D1> -TD<D2> DynCast(TD<D1> source) { - return TD<D2>(dyn_cast<D2>(source.decl)); -} - -template <class D = Decl> class DeclFromParser; -template <class D = Decl> class DeclFromUser; - -template <class D> class DeclFromParser : public TaggedASTDecl<D> { -public: - DeclFromParser() : TaggedASTDecl<D>() {} - DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) {} - - DeclFromUser<D> GetOrigin(ClangASTSource &source); -}; - -template <class D> class DeclFromUser : public TaggedASTDecl<D> { -public: - DeclFromUser() : TaggedASTDecl<D>() {} - DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) {} - - DeclFromParser<D> Import(ClangASTSource &source); -}; - -template <class D> -DeclFromUser<D> DeclFromParser<D>::GetOrigin(ClangASTSource &source) { - ClangASTImporter::DeclOrigin origin = source.GetDeclOrigin(this->decl); - if (!origin.Valid()) - return DeclFromUser<D>(); - return DeclFromUser<D>(dyn_cast<D>(origin.decl)); -} - -template <class D> -DeclFromParser<D> DeclFromUser<D>::Import(ClangASTSource &source) { - DeclFromParser<> parser_generic_decl(source.CopyDecl(this->decl)); - if (parser_generic_decl.IsInvalid()) - return DeclFromParser<D>(); - return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl)); -} - bool ClangASTSource::FindObjCMethodDeclsWithOrigin( NameSearchContext &context, ObjCInterfaceDecl *original_interface_decl, const char *log_info) { @@ -764,17 +713,18 @@ bool ClangASTSource::FindObjCMethodDeclsWithOrigin( Selector original_selector; if (decl_name.isObjCZeroArgSelector()) { - IdentifierInfo *ident = &original_ctx->Idents.get(decl_name.getAsString()); + const IdentifierInfo *ident = + &original_ctx->Idents.get(decl_name.getAsString()); original_selector = original_ctx->Selectors.getSelector(0, &ident); } else if (decl_name.isObjCOneArgSelector()) { const std::string &decl_name_string = decl_name.getAsString(); std::string decl_name_string_without_colon(decl_name_string.c_str(), decl_name_string.length() - 1); - IdentifierInfo *ident = + const IdentifierInfo *ident = &original_ctx->Idents.get(decl_name_string_without_colon); original_selector = original_ctx->Selectors.getSelector(1, &ident); } else { - SmallVector<IdentifierInfo *, 4> idents; + SmallVector<const IdentifierInfo *, 4> idents; clang::Selector sel = decl_name.getObjCSelector(); @@ -968,7 +918,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { ConstString selector_name(ss.GetString()); LLDB_LOG(log, - "ClangASTSource::FindObjCMethodDecls on (ASTContext*){0} '{1}' " + "ClangASTSource::FindObjCMethodDecls on (ASTContext*){0:x} '{1}' " "for selector [{2} {3}]", m_ast_context, m_clang_ast_context->getDisplayName(), interface_decl->getName(), selector_name); @@ -1112,7 +1062,7 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { LLDB_LOG(log, "CAS::FOPD trying origin " - "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...", complete_interface_decl, &complete_iface_decl->getASTContext()); FindObjCMethodDeclsWithOrigin(context, complete_interface_decl, @@ -1188,8 +1138,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { } while (false); } -static bool FindObjCPropertyAndIvarDeclsWithOrigin( - NameSearchContext &context, ClangASTSource &source, +bool ClangASTSource::FindObjCPropertyAndIvarDeclsWithOrigin( + NameSearchContext &context, DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl) { Log *log = GetLog(LLDBLog::Expressions); @@ -1209,7 +1159,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( if (origin_property_decl.IsValid()) { DeclFromParser<ObjCPropertyDecl> parser_property_decl( - origin_property_decl.Import(source)); + origin_property_decl.Import(m_ast_context, *m_ast_importer_sp)); if (parser_property_decl.IsValid()) { LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_property_decl.decl)); @@ -1224,7 +1174,7 @@ static bool FindObjCPropertyAndIvarDeclsWithOrigin( if (origin_ivar_decl.IsValid()) { DeclFromParser<ObjCIvarDecl> parser_ivar_decl( - origin_ivar_decl.Import(source)); + origin_ivar_decl.Import(m_ast_context, *m_ast_importer_sp)); if (parser_ivar_decl.IsValid()) { LLDB_LOG(log, " CAS::FOPD found\n{0}", ClangUtil::DumpDecl(parser_ivar_decl.decl)); @@ -1243,22 +1193,22 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl( cast<ObjCInterfaceDecl>(context.m_decl_context)); DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl( - parser_iface_decl.GetOrigin(*this)); + parser_iface_decl.GetOrigin(*m_ast_importer_sp)); ConstString class_name(parser_iface_decl->getNameAsString().c_str()); LLDB_LOG(log, "ClangASTSource::FindObjCPropertyAndIvarDecls on " - "(ASTContext*){0} '{1}' for '{2}.{3}'", + "(ASTContext*){0:x} '{1}' for '{2}.{3}'", m_ast_context, m_clang_ast_context->getDisplayName(), parser_iface_decl->getName(), context.m_decl_name.getAsString()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, origin_iface_decl)) + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, origin_iface_decl)) return; LLDB_LOG(log, "CAS::FOPD couldn't find the property on origin " - "(ObjCInterfaceDecl*){0}/(ASTContext*){1}, searching " + "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}, searching " "elsewhere...", origin_iface_decl.decl, &origin_iface_decl->getASTContext()); @@ -1283,10 +1233,10 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { LLDB_LOG(log, "CAS::FOPD trying origin " - "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...", complete_iface_decl.decl, &complete_iface_decl->getASTContext()); - FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, complete_iface_decl); + FindObjCPropertyAndIvarDeclsWithOrigin(context, complete_iface_decl); return; } while (false); @@ -1315,12 +1265,12 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { break; LLDB_LOG(log, - "CAS::FOPD[{0}] trying module " - "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + "CAS::FOPD[{0:x}] trying module " + "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...", interface_decl_from_modules.decl, &interface_decl_from_modules->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, interface_decl_from_modules)) return; } while (false); @@ -1359,12 +1309,12 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { break; LLDB_LOG(log, - "CAS::FOPD[{0}] trying runtime " - "(ObjCInterfaceDecl*){0}/(ASTContext*){1}...", + "CAS::FOPD[{0:x}] trying runtime " + "(ObjCInterfaceDecl*){0:x}/(ASTContext*){1:x}...", interface_decl_from_runtime.decl, &interface_decl_from_runtime->getASTContext()); - if (FindObjCPropertyAndIvarDeclsWithOrigin(context, *this, + if (FindObjCPropertyAndIvarDeclsWithOrigin(context, interface_decl_from_runtime)) return; } while (false); @@ -1379,7 +1329,7 @@ void ClangASTSource::LookupInNamespace(NameSearchContext &context) { ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer_sp->GetNamespaceMap(namespace_context); - LLDB_LOGV(log, " CAS::FEVD Inspecting namespace map {0} ({1} entries)", + LLDB_LOGV(log, " CAS::FEVD Inspecting namespace map {0:x} ({1} entries)", namespace_map.get(), namespace_map->size()); if (!namespace_map) @@ -1395,205 +1345,16 @@ void ClangASTSource::LookupInNamespace(NameSearchContext &context) { } } -typedef llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsetMap; -typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetMap; - -template <class D, class O> -static bool ImportOffsetMap(llvm::DenseMap<const D *, O> &destination_map, - llvm::DenseMap<const D *, O> &source_map, - ClangASTSource &source) { - // When importing fields into a new record, clang has a hard requirement that - // fields be imported in field offset order. Since they are stored in a - // DenseMap with a pointer as the key type, this means we cannot simply - // iterate over the map, as the order will be non-deterministic. Instead we - // have to sort by the offset and then insert in sorted order. - typedef llvm::DenseMap<const D *, O> MapType; - typedef typename MapType::value_type PairType; - std::vector<PairType> sorted_items; - sorted_items.reserve(source_map.size()); - sorted_items.assign(source_map.begin(), source_map.end()); - llvm::sort(sorted_items, llvm::less_second()); - - for (const auto &item : sorted_items) { - DeclFromUser<D> user_decl(const_cast<D *>(item.first)); - DeclFromParser<D> parser_decl(user_decl.Import(source)); - if (parser_decl.IsInvalid()) - return false; - destination_map.insert( - std::pair<const D *, O>(parser_decl.decl, item.second)); - } - - return true; -} - -template <bool IsVirtual> -bool ExtractBaseOffsets(const ASTRecordLayout &record_layout, - DeclFromUser<const CXXRecordDecl> &record, - BaseOffsetMap &base_offsets) { - for (CXXRecordDecl::base_class_const_iterator - bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()), - be = (IsVirtual ? record->vbases_end() : record->bases_end()); - bi != be; ++bi) { - if (!IsVirtual && bi->isVirtual()) - continue; - - const clang::Type *origin_base_type = bi->getType().getTypePtr(); - const clang::RecordType *origin_base_record_type = - origin_base_type->getAs<RecordType>(); - - if (!origin_base_record_type) - return false; - - DeclFromUser<RecordDecl> origin_base_record( - origin_base_record_type->getDecl()); - - if (origin_base_record.IsInvalid()) - return false; - - DeclFromUser<CXXRecordDecl> origin_base_cxx_record( - DynCast<CXXRecordDecl>(origin_base_record)); - - if (origin_base_cxx_record.IsInvalid()) - return false; - - CharUnits base_offset; - - if (IsVirtual) - base_offset = - record_layout.getVBaseClassOffset(origin_base_cxx_record.decl); - else - base_offset = - record_layout.getBaseClassOffset(origin_base_cxx_record.decl); - - base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>( - origin_base_cxx_record.decl, base_offset)); - } - - return true; -} - -bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, - uint64_t &alignment, - FieldOffsetMap &field_offsets, - BaseOffsetMap &base_offsets, - BaseOffsetMap &virtual_base_offsets) { - - Log *log = GetLog(LLDBLog::Expressions); - - LLDB_LOG(log, - "LayoutRecordType on (ASTContext*){0} '{1}' for (RecordDecl*)" - "{2} [name = '{3}']", - m_ast_context, m_clang_ast_context->getDisplayName(), record, - record->getName()); - - DeclFromParser<const RecordDecl> parser_record(record); - DeclFromUser<const RecordDecl> origin_record( - parser_record.GetOrigin(*this)); - - if (origin_record.IsInvalid()) - return false; - - FieldOffsetMap origin_field_offsets; - BaseOffsetMap origin_base_offsets; - BaseOffsetMap origin_virtual_base_offsets; - - TypeSystemClang::GetCompleteDecl( - &origin_record->getASTContext(), - const_cast<RecordDecl *>(origin_record.decl)); - - clang::RecordDecl *definition = origin_record.decl->getDefinition(); - if (!definition || !definition->isCompleteDefinition()) - return false; - - const ASTRecordLayout &record_layout( - origin_record->getASTContext().getASTRecordLayout(origin_record.decl)); - - int field_idx = 0, field_count = record_layout.getFieldCount(); - - for (RecordDecl::field_iterator fi = origin_record->field_begin(), - fe = origin_record->field_end(); - fi != fe; ++fi) { - if (field_idx >= field_count) - return false; // Layout didn't go well. Bail out. - - uint64_t field_offset = record_layout.getFieldOffset(field_idx); - - origin_field_offsets.insert( - std::pair<const FieldDecl *, uint64_t>(*fi, field_offset)); - - field_idx++; - } - - lldbassert(&record->getASTContext() == m_ast_context); - - DeclFromUser<const CXXRecordDecl> origin_cxx_record( - DynCast<const CXXRecordDecl>(origin_record)); - - if (origin_cxx_record.IsValid()) { - if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, - origin_base_offsets) || - !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, - origin_virtual_base_offsets)) - return false; - } - - if (!ImportOffsetMap(field_offsets, origin_field_offsets, *this) || - !ImportOffsetMap(base_offsets, origin_base_offsets, *this) || - !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, - *this)) - return false; - - size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth(); - alignment = record_layout.getAlignment().getQuantity() * - m_ast_context->getCharWidth(); - - if (log) { - LLDB_LOG(log, "LRT returned:"); - LLDB_LOG(log, "LRT Original = (RecordDecl*){0}", - static_cast<const void *>(origin_record.decl)); - LLDB_LOG(log, "LRT Size = {0}", size); - LLDB_LOG(log, "LRT Alignment = {0}", alignment); - LLDB_LOG(log, "LRT Fields:"); - for (RecordDecl::field_iterator fi = record->field_begin(), - fe = record->field_end(); - fi != fe; ++fi) { - LLDB_LOG(log, - "LRT (FieldDecl*){0}, Name = '{1}', Type = '{2}', Offset = " - "{3} bits", - *fi, fi->getName(), fi->getType().getAsString(), - field_offsets[*fi]); - } - DeclFromParser<const CXXRecordDecl> parser_cxx_record = - DynCast<const CXXRecordDecl>(parser_record); - if (parser_cxx_record.IsValid()) { - LLDB_LOG(log, "LRT Bases:"); - for (CXXRecordDecl::base_class_const_iterator - bi = parser_cxx_record->bases_begin(), - be = parser_cxx_record->bases_end(); - bi != be; ++bi) { - bool is_virtual = bi->isVirtual(); - - QualType base_type = bi->getType(); - const RecordType *base_record_type = base_type->getAs<RecordType>(); - DeclFromParser<RecordDecl> base_record(base_record_type->getDecl()); - DeclFromParser<CXXRecordDecl> base_cxx_record = - DynCast<CXXRecordDecl>(base_record); - - LLDB_LOG(log, - "LRT {0}(CXXRecordDecl*){1}, Name = '{2}', Offset = " - "{3} chars", - (is_virtual ? "Virtual " : ""), base_cxx_record.decl, - base_cxx_record.decl->getName(), - (is_virtual - ? virtual_base_offsets[base_cxx_record.decl].getQuantity() - : base_offsets[base_cxx_record.decl].getQuantity())); - } - } else { - LLDB_LOG(log, "LRD Not a CXXRecord, so no bases"); - } - } - - return true; +bool ClangASTSource::layoutRecordType( + const RecordDecl *record, uint64_t &size, uint64_t &alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &base_offsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &virtual_base_offsets) { + return m_ast_importer_sp->importRecordLayoutFromOrigin( + record, size, alignment, field_offsets, base_offsets, + virtual_base_offsets); } void ClangASTSource::CompleteNamespaceMap( @@ -1605,7 +1366,7 @@ void ClangASTSource::CompleteNamespaceMap( if (log) { if (parent_map && parent_map->size()) LLDB_LOG(log, - "CompleteNamespaceMap on (ASTContext*){0} '{1}' Searching " + "CompleteNamespaceMap on (ASTContext*){0:x} '{1}' Searching " "for namespace {2} in namespace {3}", m_ast_context, m_clang_ast_context->getDisplayName(), name, parent_map->begin()->second.GetName()); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index f3fec3f944a1..83c910477acc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -49,7 +49,7 @@ public: ~ClangASTSource() override; /// Interface stubs. - clang::Decl *GetExternalDecl(uint32_t) override { return nullptr; } + clang::Decl *GetExternalDecl(clang::GlobalDeclID) override { return nullptr; } clang::Stmt *GetExternalDeclStmt(uint64_t) override { return nullptr; } clang::Selector GetExternalSelector(uint32_t) override { return clang::Selector(); @@ -352,6 +352,11 @@ public: /// ExternalASTSource. TypeSystemClang *GetTypeSystem() const { return m_clang_ast_context; } +private: + bool FindObjCPropertyAndIvarDeclsWithOrigin( + NameSearchContext &context, + DeclFromUser<const clang::ObjCInterfaceDecl> &origin_iface_decl); + protected: bool FindObjCMethodDeclsWithOrigin( NameSearchContext &context, diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h index 7459b715dbe2..21abd71cc34e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h @@ -29,7 +29,7 @@ public: return diag->getKind() == eDiagnosticOriginClang; } - ClangDiagnostic(llvm::StringRef message, DiagnosticSeverity severity, + ClangDiagnostic(llvm::StringRef message, lldb::Severity severity, uint32_t compiler_id) : Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 2d306b42760b..f994d0250433 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -228,8 +228,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, std::string msg = llvm::formatv("redefinition of persistent variable '{0}'", name).str(); m_parser_vars->m_diagnostics->AddDiagnostic( - msg, DiagnosticSeverity::eDiagnosticSeverityError, - DiagnosticOrigin::eDiagnosticOriginLLDB); + msg, lldb::eSeverityError, DiagnosticOrigin::eDiagnosticOriginLLDB); return false; } @@ -1049,7 +1048,6 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( context.AddNamedDecl(copied_function); context.m_found_function_with_type_info = true; - context.m_found_function = true; } else if (auto copied_var = dyn_cast<clang::VarDecl>(copied_decl)) { context.AddNamedDecl(copied_var); context.m_found_variable = true; @@ -1299,7 +1297,6 @@ void ClangExpressionDeclMap::LookupFunction( AddOneFunction(context, sym_ctx.function, nullptr); context.m_found_function_with_type_info = true; - context.m_found_function = true; } else if (sym_ctx.symbol) { Symbol *symbol = sym_ctx.symbol; if (target && symbol->GetType() == eSymbolTypeReExported) { @@ -1331,10 +1328,8 @@ void ClangExpressionDeclMap::LookupFunction( if (!context.m_found_function_with_type_info) { if (extern_symbol) { AddOneFunction(context, nullptr, extern_symbol); - context.m_found_function = true; } else if (non_extern_symbol) { AddOneFunction(context, nullptr, non_extern_symbol); - context.m_found_function = true; } } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 574d661e2a21..303e88feea20 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -207,20 +207,20 @@ public: m_passthrough->HandleDiagnostic(DiagLevel, Info); m_os->flush(); - lldb_private::DiagnosticSeverity severity; + lldb::Severity severity; bool make_new_diagnostic = true; switch (DiagLevel) { case DiagnosticsEngine::Level::Fatal: case DiagnosticsEngine::Level::Error: - severity = eDiagnosticSeverityError; + severity = lldb::eSeverityError; break; case DiagnosticsEngine::Level::Warning: - severity = eDiagnosticSeverityWarning; + severity = lldb::eSeverityWarning; break; case DiagnosticsEngine::Level::Remark: case DiagnosticsEngine::Level::Ignored: - severity = eDiagnosticSeverityRemark; + severity = lldb::eSeverityInfo; break; case DiagnosticsEngine::Level::Note: m_manager->AppendMessageToDiagnostic(m_output); @@ -238,7 +238,7 @@ public: if (!clang_diag || clang_diag->HasFixIts()) break; // Ignore all Fix-Its that are not associated with an error. - if (clang_diag->GetSeverity() != eDiagnosticSeverityError) + if (clang_diag->GetSeverity() != lldb::eSeverityError) break; AddAllFixIts(clang_diag, Info); break; @@ -256,7 +256,7 @@ public: // enough context in an expression for the warning to be useful. // FIXME: Should we try to filter out FixIts that apply to our generated // code, and not the user's expression? - if (severity == eDiagnosticSeverityError) + if (severity == lldb::eSeverityError) AddAllFixIts(new_diagnostic.get(), Info); m_manager->AddDiagnostic(std::move(new_diagnostic)); @@ -392,8 +392,8 @@ ClangExpressionParser::ClangExpressionParser( // Make sure clang uses the same VFS as LLDB. m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem()); - lldb::LanguageType frame_lang = - expr.Language(); // defaults to lldb::eLanguageTypeUnknown + // Defaults to lldb::eLanguageTypeUnknown. + lldb::LanguageType frame_lang = expr.Language().AsLanguageType(); std::string abi; ArchSpec target_arch; @@ -410,7 +410,7 @@ ClangExpressionParser::ClangExpressionParser( // 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(); + frame_lang = frame_sp->GetLanguage().AsLanguageType(); if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) { LLDB_LOGF(log, "Frame has language of type %s", @@ -445,8 +445,8 @@ ClangExpressionParser::ClangExpressionParser( // Supported subsets of x86 if (target_machine == llvm::Triple::x86 || target_machine == llvm::Triple::x86_64) { - m_compiler->getTargetOpts().Features.push_back("+sse"); - m_compiler->getTargetOpts().Features.push_back("+sse2"); + m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse"); + m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse2"); } // Set the target CPU to generate code for. This will be empty for any CPU @@ -479,7 +479,7 @@ ClangExpressionParser::ClangExpressionParser( assert(m_compiler->hasTarget()); // 4. Set language options. - lldb::LanguageType language = expr.Language(); + lldb::LanguageType language = expr.Language().AsLanguageType(); LangOptions &lang_opts = m_compiler->getLangOpts(); switch (language) { @@ -526,7 +526,10 @@ ClangExpressionParser::ClangExpressionParser( [[fallthrough]]; case lldb::eLanguageTypeC_plus_plus_03: lang_opts.CPlusPlus = true; - if (process_sp) + if (process_sp + // We're stopped in a frame without debug-info. The user probably + // intends to make global queries (which should include Objective-C). + && !(frame_sp && frame_sp->HasDebugInformation())) lang_opts.ObjC = process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC) != nullptr; break; @@ -1161,7 +1164,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (m_pp_callbacks && m_pp_callbacks->hasErrors()) { num_errors++; - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "while importing modules:"); diagnostic_manager.AppendMessageToDiagnostic( m_pp_callbacks->getErrorString()); @@ -1293,7 +1296,7 @@ static bool FindFunctionInModule(ConstString &mangled_name, return false; } -lldb_private::Status ClangExpressionParser::PrepareForExecution( +lldb_private::Status ClangExpressionParser::DoPrepareForExecution( lldb::addr_t &func_addr, lldb::addr_t &func_end, lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx, bool &can_interpret, ExecutionPolicy execution_policy) { @@ -1341,10 +1344,10 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( { auto lang = m_expr.Language(); LLDB_LOGF(log, "%s - Current expression language is %s\n", __FUNCTION__, - Language::GetNameForLanguageType(lang)); + lang.GetDescription().data()); lldb::ProcessSP process_sp = exe_ctx.GetProcessSP(); if (process_sp && lang != lldb::eLanguageTypeUnknown) { - auto runtime = process_sp->GetLanguageRuntime(lang); + auto runtime = process_sp->GetLanguageRuntime(lang.AsLanguageType()); if (runtime) runtime->GetIRPasses(custom_passes); } @@ -1469,47 +1472,3 @@ lldb_private::Status ClangExpressionParser::PrepareForExecution( return err; } - -lldb_private::Status ClangExpressionParser::RunStaticInitializers( - lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx) { - lldb_private::Status err; - - lldbassert(execution_unit_sp.get()); - lldbassert(exe_ctx.HasThreadScope()); - - if (!execution_unit_sp.get()) { - err.SetErrorString( - "can't run static initializers for a NULL execution unit"); - return err; - } - - if (!exe_ctx.HasThreadScope()) { - err.SetErrorString("can't run static initializers without a thread"); - return err; - } - - std::vector<lldb::addr_t> static_initializers; - - execution_unit_sp->GetStaticInitializers(static_initializers); - - for (lldb::addr_t static_initializer : static_initializers) { - EvaluateExpressionOptions options; - - lldb::ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction( - exe_ctx.GetThreadRef(), Address(static_initializer), CompilerType(), - llvm::ArrayRef<lldb::addr_t>(), options)); - - DiagnosticManager execution_errors; - lldb::ExpressionResults results = - exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan( - exe_ctx, call_static_initializer, options, execution_errors); - - if (results != lldb::eExpressionCompleted) { - err.SetErrorStringWithFormat("couldn't run static initializer: %s", - execution_errors.GetString().c_str()); - return err; - } - } - - return err; -} diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h index 185a5a381f23..0852e928a9d4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h @@ -113,24 +113,11 @@ public: /// \return /// An error code indicating the success or failure of the operation. /// Test with Success(). - Status - PrepareForExecution(lldb::addr_t &func_addr, lldb::addr_t &func_end, - lldb::IRExecutionUnitSP &execution_unit_sp, - ExecutionContext &exe_ctx, bool &can_interpret, - lldb_private::ExecutionPolicy execution_policy) override; - - /// Run all static initializers for an execution unit. - /// - /// \param[in] execution_unit_sp - /// The execution unit. - /// - /// \param[in] exe_ctx - /// The execution context to use when running them. Thread can't be null. - /// - /// \return - /// The error code indicating the - Status RunStaticInitializers(lldb::IRExecutionUnitSP &execution_unit_sp, - ExecutionContext &exe_ctx); + Status DoPrepareForExecution( + lldb::addr_t &func_addr, lldb::addr_t &func_end, + lldb::IRExecutionUnitSP &execution_unit_sp, ExecutionContext &exe_ctx, + bool &can_interpret, + lldb_private::ExecutionPolicy execution_policy) override; /// Returns a string representing current ABI. /// diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index b48bbbecc0cd..3b601726388d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -229,7 +229,7 @@ void AddLambdaCaptureDecls(StreamString &stream, StackFrame *frame, assert(frame); if (auto thisValSP = ClangExpressionUtil::GetLambdaValueObject(frame)) { - uint32_t numChildren = thisValSP->GetNumChildren(); + uint32_t numChildren = thisValSP->GetNumChildrenIgnoringErrors(); for (uint32_t i = 0; i < numChildren; ++i) { auto childVal = thisValSP->GetChildAtIndex(i); ConstString childName(childVal ? childVal->GetName() : ConstString("")); @@ -417,7 +417,7 @@ bool ClangExpressionSourceCode::GetText( if (sc.comp_unit && sc.line_entry.IsValid()) { DebugMacros *dm = sc.comp_unit->GetDebugMacros(); if (dm) { - AddMacroState state(sc.line_entry.file, sc.line_entry.line); + AddMacroState state(sc.line_entry.GetFile(), sc.line_entry.line); AddMacros(dm, sc.comp_unit, state, debug_macros_stream); } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp index 89d9ac042e57..e746e6afe39b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -11,6 +11,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/Module.h" #include <optional> using namespace lldb_private; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h index 219ed641615e..6bd18186a567 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -10,9 +10,15 @@ #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXTERNALASTSOURCECALLBACKS_H #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "clang/Basic/Module.h" +#include "clang/Basic/ASTSourceDescriptor.h" #include <optional> +namespace clang { + +class Module; + +} // namespace clang + namespace lldb_private { class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 5235cd2a1461..59321e375bdc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -138,7 +138,7 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, type_name = clang_qual_type.GetTypeName().AsCString(""); } else { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "Could not determine type of input value %" PRIu64 ".", (uint64_t)i); return 1; @@ -194,7 +194,7 @@ ClangFunctionCaller::CompileFunction(lldb::ThreadSP thread_to_use_sp, num_errors = clang_parser->Parse(diagnostic_manager); m_parser.reset(clang_parser); } else { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "no process - unable to inject function"); num_errors = 1; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 5ce0d3537823..024fc75a5dd5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -8,7 +8,6 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" -#include "clang/Basic/DiagnosticSerialization.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" @@ -19,20 +18,15 @@ #include "clang/Sema/Lookup.h" #include "clang/Serialization/ASTReader.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" #include "ClangHost.h" #include "ClangModulesDeclVendor.h" -#include "ModuleDependencyCollector.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/Progress.h" -#include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" @@ -40,10 +34,8 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/StreamString.h" #include <memory> -#include <mutex> using namespace lldb_private; @@ -75,12 +67,11 @@ private: std::vector<IDAndDiagnostic> m_diagnostics; /// The DiagnosticPrinter used for creating the full diagnostic messages /// that are stored in m_diagnostics. - std::shared_ptr<clang::TextDiagnosticPrinter> m_diag_printer; + std::unique_ptr<clang::TextDiagnosticPrinter> m_diag_printer; /// Output stream of m_diag_printer. - std::shared_ptr<llvm::raw_string_ostream> m_os; + std::unique_ptr<llvm::raw_string_ostream> m_os; /// Output string filled by m_os. Will be reused for different diagnostics. std::string m_output; - Log *m_log; /// A Progress with explicitly managed lifetime. std::unique_ptr<Progress> m_current_progress_up; std::vector<std::string> m_module_build_stack; @@ -142,12 +133,10 @@ private: } // anonymous namespace StoringDiagnosticConsumer::StoringDiagnosticConsumer() { - m_log = GetLog(LLDBLog::Expressions); - - clang::DiagnosticOptions *m_options = new clang::DiagnosticOptions(); - m_os = std::make_shared<llvm::raw_string_ostream>(m_output); + auto *options = new clang::DiagnosticOptions(); + m_os = std::make_unique<llvm::raw_string_ostream>(m_output); m_diag_printer = - std::make_shared<clang::TextDiagnosticPrinter>(*m_os, m_options); + std::make_unique<clang::TextDiagnosticPrinter>(*m_os, options); } void StoringDiagnosticConsumer::HandleDiagnostic( @@ -191,7 +180,7 @@ void StoringDiagnosticConsumer::EndSourceFile() { bool StoringDiagnosticConsumer::HandleModuleRemark( const clang::Diagnostic &info) { - Log *log = GetLog(LLDBLog::Expressions); + Log *log = GetLog(LLDBLog::Types | LLDBLog::Expressions); switch (info.getID()) { case clang::diag::remark_module_build: { const auto &module_name = info.getArgStdStr(0); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 30bc81c9ed8c..35038a56440d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -56,6 +56,7 @@ #include "clang/AST/DeclObjC.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/BinaryFormat/Dwarf.h" using namespace lldb_private; @@ -63,22 +64,21 @@ char ClangUserExpression::ID; ClangUserExpression::ClangUserExpression( ExecutionContextScope &exe_scope, llvm::StringRef expr, - llvm::StringRef prefix, lldb::LanguageType language, - ResultType desired_type, const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) + llvm::StringRef prefix, SourceLanguage language, ResultType desired_type, + const EvaluateExpressionOptions &options, ValueObject *ctx_obj) : LLVMUserExpression(exe_scope, expr, prefix, language, desired_type, options), m_type_system_helper(*m_target_wp.lock(), options.GetExecutionPolicy() == eExecutionPolicyTopLevel), m_result_delegate(exe_scope.CalculateTarget()), m_ctx_obj(ctx_obj) { - switch (m_language) { - case lldb::eLanguageTypeC_plus_plus: + switch (m_language.name) { + case llvm::dwarf::DW_LNAME_C_plus_plus: m_allow_cxx = true; break; - case lldb::eLanguageTypeObjC: + case llvm::dwarf::DW_LNAME_ObjC: m_allow_objc = true; break; - case lldb::eLanguageTypeObjC_plus_plus: + case llvm::dwarf::DW_LNAME_ObjC_plus_plus: default: m_allow_cxx = true; m_allow_objc = true; @@ -331,12 +331,11 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man m_result_delegate.RegisterPersistentState(persistent_state); } else { diagnostic_manager.PutString( - eDiagnosticSeverityError, - "couldn't start parsing (no persistent data)"); + lldb::eSeverityError, "couldn't start parsing (no persistent data)"); return false; } } else { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "error: couldn't start parsing (no target)"); return false; } @@ -384,12 +383,11 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, // The error stream already contains several Clang diagnostics that might // be either errors or warnings, so just print them all as one remark // diagnostic to prevent that the message starts with "error: error:". - diagnostic_manager.PutString(eDiagnosticSeverityRemark, - error_stream.GetString()); + diagnostic_manager.PutString(lldb::eSeverityInfo, error_stream.GetString()); return; } - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "Unknown error while loading modules needed for " "current compilation unit."); } @@ -424,7 +422,7 @@ void ClangUserExpression::CreateSourceCode( if (!m_source_code->GetText(m_transformed_text, exe_ctx, !m_ctx_obj, for_completion, modules_to_import)) { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "couldn't construct expression body"); return; } @@ -531,7 +529,7 @@ bool ClangUserExpression::PrepareForParsing( ScanContext(exe_ctx, err); if (!err.Success()) { - diagnostic_manager.PutString(eDiagnosticSeverityWarning, err.AsCString()); + diagnostic_manager.PutString(lldb::eSeverityWarning, err.AsCString()); } //////////////////////////////////// @@ -553,9 +551,9 @@ bool ClangUserExpression::PrepareForParsing( } bool ClangUserExpression::TryParse( - DiagnosticManager &diagnostic_manager, ExecutionContextScope *exe_scope, - ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, bool generate_debug_info) { + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, + bool generate_debug_info) { m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -564,7 +562,7 @@ bool ClangUserExpression::TryParse( if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "current process state is unsuitable for expression parsing"); return false; } @@ -574,7 +572,8 @@ bool ClangUserExpression::TryParse( } m_parser = std::make_unique<ClangExpressionParser>( - exe_scope, *this, generate_debug_info, m_include_directories, m_filename); + exe_ctx.GetBestExecutionContextScope(), *this, generate_debug_info, + m_include_directories, m_filename); unsigned num_errors = m_parser->Parse(diagnostic_manager); @@ -610,9 +609,9 @@ bool ClangUserExpression::TryParse( if (!jit_error.Success()) { const char *error_cstr = jit_error.AsCString(); if (error_cstr && error_cstr[0]) - diagnostic_manager.PutString(eDiagnosticSeverityError, error_cstr); + diagnostic_manager.PutString(lldb::eSeverityError, error_cstr); else - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "expression can't be interpreted or run"); return false; } @@ -623,7 +622,8 @@ bool ClangUserExpression::TryParse( void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) { Log *log = GetLog(LLDBLog::Expressions); - CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); + CppModuleConfiguration module_config = + GetModuleConfig(m_language.AsLanguageType(), exe_ctx); m_imported_cpp_modules = module_config.GetImportedModules(); m_include_directories = module_config.GetIncludeDirs(); @@ -661,7 +661,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, Target *target = exe_ctx.GetTargetPtr(); if (!target) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); + diagnostic_manager.PutString(lldb::eSeverityError, "invalid target"); return false; } @@ -669,15 +669,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // Parse the expression // - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; - - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - bool parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, - execution_policy, keep_result_in_memory, - generate_debug_info); + bool parse_success = TryParse(diagnostic_manager, exe_ctx, execution_policy, + keep_result_in_memory, generate_debug_info); // If the expression failed to parse, check if retrying parsing with a loaded // C++ module is possible. if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) { @@ -695,9 +688,8 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // so recreate those. CreateSourceCode(retry_manager, exe_ctx, m_imported_cpp_modules, /*for_completion*/ false); - parse_success = TryParse(retry_manager, exe_scope, exe_ctx, - execution_policy, keep_result_in_memory, - generate_debug_info); + parse_success = TryParse(retry_manager, exe_ctx, execution_policy, + keep_result_in_memory, generate_debug_info); // Return the parse diagnostics if we were successful. if (parse_success) diagnostic_manager = std::move(retry_manager); @@ -706,23 +698,6 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (!parse_success) return false; - if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) { - Status static_init_error = - m_parser->RunStaticInitializers(m_execution_unit_sp, exe_ctx); - - if (!static_init_error.Success()) { - const char *error_cstr = static_init_error.AsCString(); - if (error_cstr && error_cstr[0]) - diagnostic_manager.Printf(eDiagnosticSeverityError, - "%s\n", - error_cstr); - else - diagnostic_manager.PutString(eDiagnosticSeverityError, - "couldn't run static initializers\n"); - return false; - } - } - if (m_execution_unit_sp) { bool register_execution_unit = false; @@ -741,7 +716,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, if (register_execution_unit) { if (auto *persistent_state = exe_ctx.GetTargetPtr()->GetPersistentExpressionStateForLanguage( - m_language)) + m_language.AsLanguageType())) persistent_state->RegisterExecutionUnit(m_execution_unit_sp); } } @@ -759,6 +734,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, } } + Process *process = exe_ctx.GetProcessPtr(); if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS) m_jit_process_wp = lldb::ProcessWP(process->shared_from_this()); return true; @@ -830,7 +806,7 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, if (!DeclMap()->WillParse(exe_ctx, GetMaterializer())) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "current process state is unsuitable for expression parsing"); return false; @@ -840,13 +816,8 @@ bool ClangUserExpression::Complete(ExecutionContext &exe_ctx, DeclMap()->SetLookupsEnabled(true); } - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; - - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - ClangExpressionParser parser(exe_scope, *this, false); + ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this, + false); // We have to find the source code location where the user text is inside // the transformed expression code. When creating the transformed text, we @@ -912,7 +883,7 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, if (!m_in_cplusplus_method && !m_in_objectivec_method) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "need object pointer but don't know the language"); return false; } @@ -954,7 +925,7 @@ bool ClangUserExpression::AddArguments(ExecutionContext &exe_ctx, if (!object_ptr_error.Success()) { diagnostic_manager.Printf( - eDiagnosticSeverityWarning, + lldb::eSeverityWarning, "couldn't get cmd pointer (substituting NULL): %s", object_ptr_error.AsCString()); cmd_ptr = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 7a8c095f6118..09604feea5de 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -106,8 +106,8 @@ public: /// definitions to be included when the expression is parsed. /// /// \param[in] language - /// If not eLanguageTypeUnknown, a language to use when parsing - /// the expression. Currently restricted to those languages + /// If not unknown, a language to use when parsing the + /// expression. Currently restricted to those languages /// supported by Clang. /// /// \param[in] desired_type @@ -122,7 +122,7 @@ public: /// must be evaluated. For details see the comment to /// `UserExpression::Evaluate`. ClangUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, - llvm::StringRef prefix, lldb::LanguageType language, + llvm::StringRef prefix, SourceLanguage language, ResultType desired_type, const EvaluateExpressionOptions &options, ValueObject *ctx_obj); @@ -185,9 +185,9 @@ private: /// The parameter have the same meaning as in ClangUserExpression::Parse. /// \see ClangUserExpression::Parse bool TryParse(DiagnosticManager &diagnostic_manager, - ExecutionContextScope *exe_scope, ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, - bool generate_debug_info); + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info); void SetupCppModuleImports(ExecutionContext &exe_ctx); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 56d6cf19ee4c..1f44200c4cff 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -75,8 +75,7 @@ ClangUtilityFunction::~ClangUtilityFunction() = default; bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { if (m_jit_start_addr != LLDB_INVALID_ADDRESS) { - diagnostic_manager.PutString(eDiagnosticSeverityWarning, - "already installed"); + diagnostic_manager.PutString(lldb::eSeverityWarning, "already installed"); return false; } @@ -87,21 +86,21 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, Target *target = exe_ctx.GetTargetPtr(); if (!target) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); + diagnostic_manager.PutString(lldb::eSeverityError, "invalid target"); return false; } Process *process = exe_ctx.GetProcessPtr(); if (!process) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid process"); + diagnostic_manager.PutString(lldb::eSeverityError, "invalid process"); return false; } // Since we might need to call allocate memory and maybe call code to make // the caller, we need to be stopped. if (process->GetState() != lldb::eStateStopped) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "process running"); + diagnostic_manager.PutString(lldb::eSeverityError, "process running"); return false; } ////////////////////////// @@ -114,7 +113,7 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, if (!DeclMap()->WillParse(exe_ctx, nullptr)) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "current process state is unsuitable for expression parsing"); return false; } @@ -166,9 +165,9 @@ bool ClangUtilityFunction::Install(DiagnosticManager &diagnostic_manager, } else { const char *error_cstr = jit_error.AsCString(); if (error_cstr && error_cstr[0]) { - diagnostic_manager.Printf(eDiagnosticSeverityError, "%s", error_cstr); + diagnostic_manager.Printf(lldb::eSeverityError, "%s", error_cstr); } else { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "expression can't be interpreted or run"); } return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index f43a04488230..f3aabc12f92b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -71,7 +71,7 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f, // If the path is in the libc++ include directory use it as the found libc++ // path. Ignore subdirectories such as /c++/v1/experimental as those don't // need to be specified in the header search. - if (libcpp_regex.match(f.GetPath()) && + if (libcpp_regex.match(convert_to_slash(f.GetPath())) && parent_path(posix_dir, Style::posix).ends_with("c++")) { if (!m_std_inc.TrySet(posix_dir)) return false; diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 597873af8b2a..cc9bd14c6194 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -1449,7 +1449,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { Argument *argument = &*iter; - if (argument->getName().equals("this")) { + if (argument->getName() == "this") { ++iter; if (iter == llvm_function.arg_end()) { @@ -1461,7 +1461,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { } argument = &*iter; - } else if (argument->getName().equals("self")) { + } else if (argument->getName() == "self") { ++iter; if (iter == llvm_function.arg_end()) { @@ -1472,7 +1472,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { return false; } - if (!iter->getName().equals("_cmd")) { + if (iter->getName() != "_cmd") { m_error_stream.Format("Internal error [IRForTarget]: Wrapper takes '{0}' " "after 'self' argument (should take '_cmd')", iter->getName()); @@ -1493,7 +1493,7 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { argument = &*iter; } - if (!argument->getName().equals("$__lldb_arg")) { + if (argument->getName() != "$__lldb_arg") { m_error_stream.Format("Internal error [IRForTarget]: Wrapper takes an " "argument named '{0}' instead of the struct pointer", argument->getName()); diff --git a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h index dc8621dd6aba..9a3320636081 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h +++ b/contrib/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.h @@ -41,7 +41,6 @@ struct NameSearchContext { bool m_found_variable = false; bool m_found_function_with_type_info = false; - bool m_found_function = false; bool m_found_local_vars_nsp = false; bool m_found_type = false; diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index b652ede9b1f5..147c00e51b40 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -831,7 +831,7 @@ uint32_t EmulateInstructionARM::GetFramePointerRegisterNumber() const { case llvm::Triple::TvOS: case llvm::Triple::WatchOS: case llvm::Triple::XROS: - // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: + case llvm::Triple::BridgeOS: is_apple = true; break; default: diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp index 6ca4fb052457..62ecac3e0831 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp @@ -444,6 +444,8 @@ bool EmulateInstructionARM64::CreateFunctionEntryUnwind( // Our previous Call Frame Address is the stack pointer row->GetCFAValue().SetIsRegisterPlusOffset(gpr_sp_arm64, 0); + row->SetRegisterLocationToSame(gpr_lr_arm64, /*must_replace=*/false); + row->SetRegisterLocationToSame(gpr_fp_arm64, /*must_replace=*/false); unwind_plan.AppendRow(row); unwind_plan.SetSourceName("EmulateInstructionARM64"); diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp b/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp index 6c46618b337c..e8014b1eeb37 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.cpp @@ -622,11 +622,26 @@ std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) { Log *log = GetLog(LLDBLog::Unwind); uint16_t try_rvc = uint16_t(inst & 0x0000ffff); - // check whether the compressed encode could be valid - uint16_t mask = try_rvc & 0b11; - bool is_rvc = try_rvc != 0 && mask != 3; uint8_t inst_type = RV64; + // Try to get size of RISCV instruction. + // 1.2 Instruction Length Encoding + bool is_16b = (inst & 0b11) != 0b11; + bool is_32b = (inst & 0x1f) != 0x1f; + bool is_48b = (inst & 0x3f) != 0x1f; + bool is_64b = (inst & 0x7f) != 0x3f; + if (is_16b) + m_last_size = 2; + else if (is_32b) + m_last_size = 4; + else if (is_48b) + m_last_size = 6; + else if (is_64b) + m_last_size = 8; + else + // Not Valid + m_last_size = std::nullopt; + // if we have ArchSpec::eCore_riscv128 in the future, // we also need to check it here if (m_arch.GetCore() == ArchSpec::eCore_riscv32) @@ -638,8 +653,8 @@ std::optional<DecodeResult> EmulateInstructionRISCV::Decode(uint32_t inst) { LLDB_LOGF( log, "EmulateInstructionRISCV::%s: inst(%x at %" PRIx64 ") was decoded to %s", __FUNCTION__, inst, m_addr, pat.name); - auto decoded = is_rvc ? pat.decode(try_rvc) : pat.decode(inst); - return DecodeResult{decoded, inst, is_rvc, pat}; + auto decoded = is_16b ? pat.decode(try_rvc) : pat.decode(inst); + return DecodeResult{decoded, inst, is_16b, pat}; } } LLDB_LOGF(log, "EmulateInstructionRISCV::%s: inst(0x%x) was unsupported", diff --git a/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h b/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h index 8bca73a7f589..53ac11c2e110 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h +++ b/contrib/llvm-project/lldb/source/Plugins/Instruction/RISCV/EmulateInstructionRISCV.h @@ -60,6 +60,7 @@ public: bool SetTargetTriple(const ArchSpec &arch) override; bool ReadInstruction() override; + std::optional<uint32_t> GetLastInstrSize() override { return m_last_size; } bool EvaluateInstruction(uint32_t options) override; bool TestEmulation(Stream &out_stream, ArchSpec &arch, OptionValueDictionary *test_data) override; @@ -99,6 +100,8 @@ public: private: /// Last decoded instruction from m_opcode DecodeResult m_decoded; + /// Last decoded instruction size estimate. + std::optional<uint32_t> m_last_size; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp index d84cd36d7ce1..cd91f4a6ff1b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/ASanLibsanitizers/InstrumentationRuntimeASanLibsanitizers.cpp @@ -90,9 +90,16 @@ void InstrumentationRuntimeASanLibsanitizers::Activate() { if (!process_sp) return; + lldb::ModuleSP module_sp = GetRuntimeModuleSP(); + Breakpoint *breakpoint = ReportRetriever::SetupBreakpoint( - GetRuntimeModuleSP(), process_sp, - ConstString("_Z22raise_sanitizers_error23sanitizer_error_context")); + module_sp, process_sp, ConstString("sanitizers_address_on_report")); + + if (!breakpoint) { + breakpoint = ReportRetriever::SetupBreakpoint( + module_sp, process_sp, + ConstString("_Z22raise_sanitizers_error23sanitizer_error_context")); + } if (!breakpoint) return; diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index 72293c5331f4..b2781aa5e7db 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -27,6 +27,8 @@ #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" @@ -211,7 +213,7 @@ CreateStackTrace(ValueObjectSP o, auto trace_sp = std::make_shared<StructuredData::Array>(); ValueObjectSP trace_value_object = o->GetValueForExpressionPath(trace_item_name.c_str()); - size_t count = trace_value_object->GetNumChildren(); + size_t count = trace_value_object->GetNumChildrenIgnoringErrors(); for (size_t j = 0; j < count; j++) { addr_t trace_addr = trace_value_object->GetChildAtIndex(j)->GetValueAsUnsigned(0); diff --git a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp index ff58c4cababa..298b63bc716f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp @@ -219,6 +219,7 @@ bool ReportRetriever::NotifyBreakpointHit(ProcessSP process_sp, return true; // Return true to stop the target } +// FIXME: Setup the breakpoint using a less fragile SPI. rdar://124399066 Breakpoint *ReportRetriever::SetupBreakpoint(ModuleSP module_sp, ProcessSP process_sp, ConstString symbol_name) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 314a4aca8d26..2c9b3c425397 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -12,6 +12,7 @@ #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" @@ -74,17 +75,17 @@ public: ~BlockPointerSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override { + llvm::Expected<uint32_t> CalculateNumChildren() override { const bool omit_empty_base_classes = false; return m_block_struct_type.GetNumChildren(omit_empty_base_classes, nullptr); } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { if (!m_block_struct_type.IsValid()) { return lldb::ValueObjectSP(); } - if (idx >= CalculateNumChildren()) { + if (idx >= CalculateNumChildrenIgnoringErrors()) { return lldb::ValueObjectSP(); } @@ -105,13 +106,16 @@ public: bool child_is_deref_of_parent = false; uint64_t language_flags = 0; - const CompilerType child_type = - m_block_struct_type.GetChildCompilerTypeAtIndex( - &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, - ignore_array_bounds, child_name, child_byte_size, child_byte_offset, - child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, value_object, - language_flags); + auto child_type_or_err = m_block_struct_type.GetChildCompilerTypeAtIndex( + &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, value_object, language_flags); + if (!child_type_or_err) + return ValueObjectConstResult::Create( + exe_ctx.GetBestExecutionContextScope(), + Status(child_type_or_err.takeError())); + CompilerType child_type = *child_type_or_err; ValueObjectSP struct_pointer_sp = m_backend.Cast(m_block_struct_type.GetPointerType()); @@ -136,7 +140,9 @@ public: // return true if this object is now safe to use forever without ever // updating again; the typical (and tested) answer here is 'false' - bool Update() override { return false; } + lldb::ChildCacheState Update() override { + return lldb::ChildCacheState::eRefetch; + } // maybe return false if the block pointer is, say, null bool MightHaveChildren() override { return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index f0fe6c9e06d9..06c827c2543f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -152,7 +152,7 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) { // because it is significantly more efficient then using the general purpose // regular expression library. size_t idx = 0; - if (basename.size() > 0 && basename[0] == '~') + if (basename.starts_with('~')) idx = 1; if (basename.size() <= idx) @@ -744,73 +744,85 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { cpp_category_sp, lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator, "libc++ std::bitset synthetic children", - "^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$", stl_deref_flags, true); + "^std::__[[:alnum:]]+::bitset<.+>$", stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", - "^std::__[[:alnum:]]+::vector<.+>(( )?&)?$", stl_deref_flags, true); + "^std::__[[:alnum:]]+::vector<.+>$", stl_deref_flags, true); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator, + "libc++ std::valarray synthetic children", + "^std::__[[:alnum:]]+::valarray<.+>$", stl_deref_flags, true); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator, + "libc++ std::slice_array synthetic children", + "^std::__[[:alnum:]]+::slice_array<.+>$", stl_deref_flags, true); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator, + "libc++ synthetic children for the valarray proxy arrays", + "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$", + stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator, "libc++ std::forward_list synthetic children", - "^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$", stl_synth_flags, true); + "^std::__[[:alnum:]]+::forward_list<.+>$", stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", - // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$" - // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$" + // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$" + // so that it does not clash with: "^std::(__cxx11::)?list<.+>$" "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|" - "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$", + "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$", stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, - "libc++ std::map synthetic children", - "^std::__[[:alnum:]]+::map<.+> >(( )?&)?$", stl_synth_flags, true); + "libc++ std::map synthetic children", "^std::__[[:alnum:]]+::map<.+> >$", + stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, - "libc++ std::set synthetic children", - "^std::__[[:alnum:]]+::set<.+> >(( )?&)?$", stl_deref_flags, true); + "libc++ std::set synthetic children", "^std::__[[:alnum:]]+::set<.+> >$", + stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", - "^std::__[[:alnum:]]+::multiset<.+> >(( )?&)?$", stl_deref_flags, true); + "^std::__[[:alnum:]]+::multiset<.+> >$", stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", - "^std::__[[:alnum:]]+::multimap<.+> >(( )?&)?$", stl_synth_flags, true); + "^std::__[[:alnum:]]+::multimap<.+> >$", stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, "libc++ std::unordered containers synthetic children", - "^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$", + "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$", stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, "libc++ std::initializer_list synthetic children", - "^std::initializer_list<.+>(( )?&)?$", stl_synth_flags, true); + "^std::initializer_list<.+>$", stl_synth_flags, true); AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator, "libc++ std::queue synthetic children", - "^std::__[[:alnum:]]+::queue<.+>(( )?&)?$", stl_synth_flags, - true); + "^std::__[[:alnum:]]+::queue<.+>$", stl_synth_flags, true); AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator, "libc++ std::tuple synthetic children", - "^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$", stl_synth_flags, - true); + "^std::__[[:alnum:]]+::tuple<.*>$", stl_synth_flags, true); AddCXXSynthetic(cpp_category_sp, LibcxxOptionalSyntheticFrontEndCreator, "libc++ std::optional synthetic children", - "^std::__[[:alnum:]]+::optional<.+>(( )?&)?$", - stl_synth_flags, true); + "^std::__[[:alnum:]]+::optional<.+>$", stl_synth_flags, true); AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator, "libc++ std::variant synthetic children", - "^std::__[[:alnum:]]+::variant<.+>(( )?&)?$", stl_synth_flags, - true); + "^std::__[[:alnum:]]+::variant<.+>$", stl_synth_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, @@ -819,17 +831,16 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdSpanSyntheticFrontEndCreator, - "libc++ std::span synthetic children", - "^std::__[[:alnum:]]+::span<.+>(( )?&)?$", stl_deref_flags, true); + "libc++ std::span synthetic children", "^std::__[[:alnum:]]+::span<.+>$", + stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEndCreator, "libc++ std::ranges::ref_view synthetic children", - "^std::__[[:alnum:]]+::ranges::ref_view<.+>(( )?&)?$", stl_deref_flags, - true); + "^std::__[[:alnum:]]+::ranges::ref_view<.+>$", stl_deref_flags, true); cpp_category_sp->AddTypeSynthetic( - "^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$", eFormatterMatchRegex, + "^std::__[[:alnum:]]+::deque<.+>$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); @@ -837,11 +848,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, - "shared_ptr synthetic children", - "^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$", stl_synth_flags, true); + "shared_ptr synthetic children", "^std::__[[:alnum:]]+::shared_ptr<.+>$", + stl_synth_flags, true); static constexpr const char *const libcxx_std_unique_ptr_regex = - "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"; + "^std::__[[:alnum:]]+::unique_ptr<.+>$"; AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, @@ -851,15 +862,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, - "weak_ptr synthetic children", - "^(std::__[[:alnum:]]+::)weak_ptr<.+>(( )?&)?$", stl_synth_flags, true); + "weak_ptr synthetic children", "^std::__[[:alnum:]]+::weak_ptr<.+>$", + stl_synth_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxFunctionSummaryProvider, "libc++ std::function summary provider", "^std::__[[:alnum:]]+::function<.+>$", stl_summary_flags, true); static constexpr const char *const libcxx_std_coroutine_handle_regex = - "^std::__[[:alnum:]]+::coroutine_handle<.+>(( )?&)?$"; + "^std::__[[:alnum:]]+::coroutine_handle<.+>$"; AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEndCreator, @@ -868,89 +879,100 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(false); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::bitset summary provider", - "^std::__[[:alnum:]]+::bitset<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::vector summary provider", - "^std::__[[:alnum:]]+::vector<.+>(( )?&)?$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::list summary provider", - "^std::__[[:alnum:]]+::forward_list<.+>(( )?&)?$", + "libc++ std::bitset summary provider", + "^std::__[[:alnum:]]+::bitset<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::vector summary provider", + "^std::__[[:alnum:]]+::vector<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::valarray summary provider", + "^std::__[[:alnum:]]+::valarray<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxStdSliceArraySummaryProvider, + "libc++ std::slice_array summary provider", + "^std::__[[:alnum:]]+::slice_array<.+>$", stl_summary_flags, + true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ summary provider for the valarray proxy arrays", + "^std::__[[:alnum:]]+::(gslice|mask|indirect)_array<.+>$", stl_summary_flags, true); AddCXXSummary( cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", - // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>(( )?&)?$" - // so that it does not clash with: "^std::(__cxx11::)?list<.+>(( )?&)?$" - "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|" - "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>(( )?&)?$", - stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::map summary provider", - "^std::__[[:alnum:]]+::map<.+>(( )?&)?$", stl_summary_flags, true); + "^std::__[[:alnum:]]+::forward_list<.+>$", stl_summary_flags, true); AddCXXSummary( cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::deque summary provider", - "^std::__[[:alnum:]]+::deque<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::queue summary provider", - "^std::__[[:alnum:]]+::queue<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::set summary provider", - "^std::__[[:alnum:]]+::set<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::multiset summary provider", - "^std::__[[:alnum:]]+::multiset<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::multimap summary provider", - "^std::__[[:alnum:]]+::multimap<.+>(( )?&)?$", stl_summary_flags, true); + "libc++ std::list summary provider", + // A POSIX variant of: "^std::__(?!cxx11:)[[:alnum:]]+::list<.+>$" + // so that it does not clash with: "^std::(__cxx11::)?list<.+>$" + "^std::__([A-Zabd-z0-9]|cx?[A-Za-wyz0-9]|cxx1?[A-Za-z02-9]|" + "cxx11[[:alnum:]])[[:alnum:]]*::list<.+>$", + stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::map summary provider", + "^std::__[[:alnum:]]+::map<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::deque summary provider", + "^std::__[[:alnum:]]+::deque<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::queue summary provider", + "^std::__[[:alnum:]]+::queue<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::set summary provider", + "^std::__[[:alnum:]]+::set<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::multiset summary provider", + "^std::__[[:alnum:]]+::multiset<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::multimap summary provider", + "^std::__[[:alnum:]]+::multimap<.+>$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::unordered containers summary provider", - "^(std::__[[:alnum:]]+::)unordered_(multi)?(map|set)<.+> >$", + "^std::__[[:alnum:]]+::unordered_(multi)?(map|set)<.+> >$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider, "libc++ std::tuple summary provider", - "^std::__[[:alnum:]]+::tuple<.*>(( )?&)?$", stl_summary_flags, - true); + "^std::__[[:alnum:]]+::tuple<.*>$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, "libc++ std::atomic summary provider", "^std::__[[:alnum:]]+::atomic<.+>$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::GenericOptionalSummaryProvider, - "libc++ std::optional summary provider", - "^std::__[[:alnum:]]+::optional<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxVariantSummaryProvider, - "libc++ std::variant summary provider", - "^std::__[[:alnum:]]+::variant<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, - "libc++ std::span summary provider", - "^std::__[[:alnum:]]+::span<.+>(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::GenericOptionalSummaryProvider, + "libc++ std::optional summary provider", + "^std::__[[:alnum:]]+::optional<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxVariantSummaryProvider, + "libc++ std::variant summary provider", + "^std::__[[:alnum:]]+::variant<.+>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::span summary provider", + "^std::__[[:alnum:]]+::span<.+>$", stl_summary_flags, true); stl_summary_flags.SetSkipPointers(true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::shared_ptr summary provider", - "^std::__[[:alnum:]]+::shared_ptr<.+>(( )?&)?$", - stl_summary_flags, true); + "^std::__[[:alnum:]]+::shared_ptr<.+>$", stl_summary_flags, + true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxSmartPointerSummaryProvider, "libc++ std::weak_ptr summary provider", - "^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$", - stl_summary_flags, true); + "^std::__[[:alnum:]]+::weak_ptr<.+>$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::LibcxxUniquePointerSummaryProvider, "libc++ std::unique_ptr summary provider", @@ -1039,7 +1061,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::chrono::sys_seconds summary provider", "^std::__[[:alnum:]]+::chrono::time_point<" "std::__[[:alnum:]]+::chrono::system_clock, " - "std::__[[:alnum:]]+::chrono::duration<long long, " + "std::__[[:alnum:]]+::chrono::duration<.*, " "std::__[[:alnum:]]+::ratio<1, 1> " "> >$", eTypeOptionHideChildren | eTypeOptionHideValue | @@ -1057,6 +1079,29 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { eTypeOptionCascade, true); + AddCXXSummary( + cpp_category_sp, + lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider, + "libc++ std::chrono::local_seconds summary provider", + "^std::__[[:alnum:]]+::chrono::time_point<" + "std::__[[:alnum:]]+::chrono::local_t, " + "std::__[[:alnum:]]+::chrono::duration<.*, " + "std::__[[:alnum:]]+::ratio<1, 1> " + "> >$", + eTypeOptionHideChildren | eTypeOptionHideValue | eTypeOptionCascade, + true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider, + "libc++ std::chrono::local_seconds summary provider", + "^std::__[[:alnum:]]+::chrono::time_point<" + "std::__[[:alnum:]]+::chrono::local_t, " + "std::__[[:alnum:]]+::chrono::duration<int, " + "std::__[[:alnum:]]+::ratio<86400, 1> " + "> >$", + eTypeOptionHideChildren | eTypeOptionHideValue | + eTypeOptionCascade, + true); + // Chrono calendar types cpp_category_sp->AddTypeSummary( diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp index 6aeae97667c1..5e63d1d7b214 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.cpp @@ -11,6 +11,8 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/VariableList.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" using namespace lldb; using namespace lldb_private; @@ -22,7 +24,7 @@ static lldb::addr_t GetCoroFramePtrFromHandle(ValueObjectSP valobj_sp) { // We expect a single pointer in the `coroutine_handle` class. // We don't care about its name. - if (valobj_sp->GetNumChildren() != 1) + if (valobj_sp->GetNumChildrenIgnoringErrors() != 1) return LLDB_INVALID_ADDRESS; ValueObjectSP ptr_sp(valobj_sp->GetChildAtIndex(0)); if (!ptr_sp) @@ -104,8 +106,8 @@ lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: ~StdlibCoroutineHandleSyntheticFrontEnd() = default; -size_t lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + StdlibCoroutineHandleSyntheticFrontEnd::CalculateNumChildren() { if (!m_resume_ptr_sp || !m_destroy_ptr_sp) return 0; @@ -113,7 +115,7 @@ size_t lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: } lldb::ValueObjectSP lldb_private::formatters:: - StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(size_t idx) { + StdlibCoroutineHandleSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { switch (idx) { case 0: return m_resume_ptr_sp; @@ -125,24 +127,24 @@ lldb::ValueObjectSP lldb_private::formatters:: return lldb::ValueObjectSP(); } -bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd::Update() { m_resume_ptr_sp.reset(); m_destroy_ptr_sp.reset(); m_promise_ptr_sp.reset(); ValueObjectSP valobj_sp = m_backend.GetNonSyntheticValue(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; lldb::addr_t frame_ptr_addr = GetCoroFramePtrFromHandle(valobj_sp); if (frame_ptr_addr == 0 || frame_ptr_addr == LLDB_INVALID_ADDRESS) - return false; + return lldb::ChildCacheState::eRefetch; auto ts = valobj_sp->GetCompilerType().GetTypeSystem(); auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); if (!ast_ctx) - return false; + return lldb::ChildCacheState::eRefetch; // Create the `resume` and `destroy` children. lldb::TargetSP target_sp = m_backend.GetTargetSP(); @@ -165,7 +167,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: CompilerType promise_type( valobj_sp->GetCompilerType().GetTypeTemplateArgument(0)); if (!promise_type) - return false; + return lldb::ChildCacheState::eRefetch; // Try to infer the promise_type if it was type-erased if (promise_type.IsVoidType()) { @@ -180,7 +182,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: // If we don't know the promise type, we don't display the `promise` member. // `CreateValueObjectFromAddress` below would fail for `void` types. if (promise_type.IsVoidType()) { - return false; + return lldb::ChildCacheState::eRefetch; } // Add the `promise` member. We intentionally add `promise` as a pointer type @@ -194,7 +196,7 @@ bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: if (error.Success()) m_promise_ptr_sp = promisePtr->Clone(ConstString("promise")); - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::StdlibCoroutineHandleSyntheticFrontEnd:: diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h index b26cc9ed6132..1d4bc65e2637 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/Coroutines.h @@ -34,11 +34,11 @@ public: ~StdlibCoroutineHandleSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp index 2876efc5c41a..33955dccb6cc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp @@ -33,9 +33,11 @@ public: } bool MightHaveChildren() override { return true; } - bool Update() override; - size_t CalculateNumChildren() override { return m_elements.size(); } - ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ChildCacheState Update() override; + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_elements.size(); + } + ValueObjectSP GetChildAtIndex(uint32_t idx) override; private: llvm::StringRef GetDataContainerMemberName(); @@ -78,13 +80,13 @@ llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() { llvm_unreachable("Unknown StdLib enum"); } -bool GenericBitsetFrontEnd::Update() { +lldb::ChildCacheState GenericBitsetFrontEnd::Update() { m_elements.clear(); m_first = nullptr; TargetSP target_sp = m_backend.GetTargetSP(); if (!target_sp) - return false; + return lldb::ChildCacheState::eRefetch; size_t size = 0; @@ -94,10 +96,10 @@ bool GenericBitsetFrontEnd::Update() { m_elements.assign(size, ValueObjectSP()); m_first = m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get(); - return false; + return lldb::ChildCacheState::eRefetch; } -ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(size_t idx) { +ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx >= m_elements.size() || !m_first) return ValueObjectSP(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp index 7415e915844f..23756de7f1e6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp @@ -19,7 +19,7 @@ using namespace lldb_private; bool lldb_private::formatters::GenericOptionalSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { stream.Printf(" Has Value=%s ", - valobj.GetNumChildren() == 0 ? "false" : "true"); + valobj.GetNumChildrenIgnoringErrors() == 0 ? "false" : "true"); return true; } @@ -41,10 +41,12 @@ public: } bool MightHaveChildren() override { return true; } - size_t CalculateNumChildren() override { return m_has_value ? 1U : 0U; } + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_has_value ? 1U : 0U; + } - ValueObjectSP GetChildAtIndex(size_t idx) override; - bool Update() override; + ValueObjectSP GetChildAtIndex(uint32_t idx) override; + lldb::ChildCacheState Update() override; private: bool m_has_value = false; @@ -61,7 +63,7 @@ GenericOptionalFrontend::GenericOptionalFrontend(ValueObject &valobj, } } -bool GenericOptionalFrontend::Update() { +lldb::ChildCacheState GenericOptionalFrontend::Update() { ValueObjectSP engaged_sp; if (m_stdlib == StdLib::LibCxx) @@ -71,17 +73,17 @@ bool GenericOptionalFrontend::Update() { ->GetChildMemberWithName("_M_engaged"); if (!engaged_sp) - return false; + return lldb::ChildCacheState::eRefetch; // _M_engaged/__engaged is a bool flag and is true if the optional contains a // value. Converting it to unsigned gives us a size of 1 if it contains a // value and 0 if not. m_has_value = engaged_sp->GetValueAsUnsigned(0) != 0; - return false; + return lldb::ChildCacheState::eRefetch; } -ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(size_t _idx) { +ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) { if (!m_has_value) return ValueObjectSP(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 060324e2fcfe..feaa51a96843 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -63,7 +63,7 @@ lldb::ValueObjectSP lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair( ValueObject &pair) { ValueObjectSP value; - if (pair.GetNumChildren() > 1) { + if (pair.GetNumChildrenIgnoringErrors() > 1) { ValueObjectSP second_child = pair.GetChildAtIndex(1); if (second_child) { value = second_child->GetChildMemberWithName("__value_"); @@ -106,13 +106,13 @@ bool lldb_private::formatters::LibcxxFunctionSummaryProvider( case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda: stream.Printf( " Lambda in File %s at Line %u", - callable_info.callable_line_entry.file.GetFilename().GetCString(), + callable_info.callable_line_entry.GetFile().GetFilename().GetCString(), callable_info.callable_line_entry.line); break; case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject: stream.Printf( " Function in File %s at Line %u", - callable_info.callable_line_entry.file.GetFilename().GetCString(), + callable_info.callable_line_entry.GetFile().GetFilename().GetCString(), callable_info.callable_line_entry.line); break; case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction: @@ -203,345 +203,6 @@ bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( } /* - (lldb) fr var ibeg --raw --ptr-depth 1 - (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, - std::__1::basic_string<char, std::__1::char_traits<char>, - std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, - std::__1::basic_string<char, std::__1::char_traits<char>, - std::__1::allocator<char> > >, void *> *, long> >) ibeg = { - __i_ = { - __ptr_ = 0x0000000100103870 { - std::__1::__tree_node_base<void *> = { - std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = { - __left_ = 0x0000000000000000 - } - __right_ = 0x0000000000000000 - __parent_ = 0x00000001001038b0 - __is_black_ = true - } - __value_ = { - first = 0 - second = { std::string } - */ - -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() { - if (valobj_sp) - Update(); -} - -bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { - m_pair_sp.reset(); - m_pair_ptr = nullptr; - - ValueObjectSP valobj_sp = m_backend.GetSP(); - if (!valobj_sp) - return false; - - TargetSP target_sp(valobj_sp->GetTargetSP()); - - if (!target_sp) - return false; - - if (!valobj_sp) - return false; - - // this must be a ValueObject* because it is a child of the ValueObject we - // are producing children for it if were a ValueObjectSP, we would end up - // with a loop (iterator -> synthetic -> child -> parent == iterator) and - // that would in turn leak memory by never allowing the ValueObjects to die - // and free their memory - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_->__value_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - - if (!m_pair_ptr) { - m_pair_ptr = valobj_sp - ->GetValueForExpressionPath( - ".__i_.__ptr_", nullptr, nullptr, - ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None), - nullptr) - .get(); - if (m_pair_ptr) { - auto __i_(valobj_sp->GetChildMemberWithName("__i_")); - if (!__i_) { - m_pair_ptr = nullptr; - return false; - } - CompilerType pair_type( - __i_->GetCompilerType().GetTypeTemplateArgument(0)); - std::string name; - uint64_t bit_offset_ptr; - uint32_t bitfield_bit_size_ptr; - bool is_bitfield_ptr; - pair_type = pair_type.GetFieldAtIndex( - 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); - if (!pair_type) { - m_pair_ptr = nullptr; - return false; - } - - auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS)); - m_pair_ptr = nullptr; - if (addr && addr != LLDB_INVALID_ADDRESS) { - auto ts = pair_type.GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); - if (!ast_ctx) - return false; - - // Mimick layout of std::__tree_iterator::__ptr_ and read it in - // from process memory. - // - // The following shows the contiguous block of memory: - // - // +-----------------------------+ class __tree_end_node - // __ptr_ | pointer __left_; | - // +-----------------------------+ class __tree_node_base - // | pointer __right_; | - // | __parent_pointer __parent_; | - // | bool __is_black_; | - // +-----------------------------+ class __tree_node - // | __node_value_type __value_; | <<< our key/value pair - // +-----------------------------+ - // - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( - llvm::StringRef(), - {{"ptr0", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr1", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr2", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, - {"payload", pair_type}}); - std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); - if (!size) - return false; - WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); - ProcessSP process_sp(target_sp->GetProcessSP()); - Status error; - process_sp->ReadMemory(addr, buffer_sp->GetBytes(), - buffer_sp->GetByteSize(), error); - if (error.Fail()) - return false; - DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - auto pair_sp = CreateValueObjectFromData( - "pair", extractor, valobj_sp->GetExecutionContextRef(), - tree_node_type); - if (pair_sp) - m_pair_sp = pair_sp->GetChildAtIndex(4); - } - } - } - - return false; -} - -size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - CalculateNumChildren() { - return 2; -} - -lldb::ValueObjectSP -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { - if (m_pair_ptr) - return m_pair_ptr->GetChildAtIndex(idx); - if (m_pair_sp) - return m_pair_sp->GetChildAtIndex(idx); - return lldb::ValueObjectSP(); -} - -bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - MightHaveChildren() { - return true; -} - -size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - GetIndexOfChildWithName(ConstString name) { - if (name == "first") - return 0; - if (name == "second") - return 1; - return UINT32_MAX; -} - -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: - ~LibCxxMapIteratorSyntheticFrontEnd() { - // this will be deleted when its parent dies (since it's a child object) - // delete m_pair_ptr; -} - -SyntheticChildrenFrontEnd * -lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) - : nullptr); -} - -lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: - LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp) { - if (valobj_sp) - Update(); -} - -bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: - Update() { - m_pair_sp.reset(); - m_iter_ptr = nullptr; - - ValueObjectSP valobj_sp = m_backend.GetSP(); - if (!valobj_sp) - return false; - - TargetSP target_sp(valobj_sp->GetTargetSP()); - - if (!target_sp) - return false; - - if (!valobj_sp) - return false; - - auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions() - .DontCheckDotVsArrowSyntax() - .SetSyntheticChildrenTraversal( - ValueObject::GetValueForExpressionPathOptions:: - SyntheticChildrenTraversal::None); - - // This must be a ValueObject* because it is a child of the ValueObject we - // are producing children for it if were a ValueObjectSP, we would end up - // with a loop (iterator -> synthetic -> child -> parent == iterator) and - // that would in turn leak memory by never allowing the ValueObjects to die - // and free their memory. - m_iter_ptr = - valobj_sp - ->GetValueForExpressionPath(".__i_.__node_", nullptr, nullptr, - exprPathOptions, nullptr) - .get(); - - if (m_iter_ptr) { - auto iter_child(valobj_sp->GetChildMemberWithName("__i_")); - if (!iter_child) { - m_iter_ptr = nullptr; - return false; - } - - CompilerType node_type(iter_child->GetCompilerType() - .GetTypeTemplateArgument(0) - .GetPointeeType()); - - CompilerType pair_type(node_type.GetTypeTemplateArgument(0)); - - std::string name; - uint64_t bit_offset_ptr; - uint32_t bitfield_bit_size_ptr; - bool is_bitfield_ptr; - - pair_type = pair_type.GetFieldAtIndex( - 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); - if (!pair_type) { - m_iter_ptr = nullptr; - return false; - } - - uint64_t addr = m_iter_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS); - m_iter_ptr = nullptr; - - if (addr == 0 || addr == LLDB_INVALID_ADDRESS) - return false; - - auto ts = pair_type.GetTypeSystem(); - auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>(); - if (!ast_ctx) - return false; - - // Mimick layout of std::__hash_iterator::__node_ and read it in - // from process memory. - // - // The following shows the contiguous block of memory: - // - // +-----------------------------+ class __hash_node_base - // __node_ | __next_pointer __next_; | - // +-----------------------------+ class __hash_node - // | size_t __hash_; | - // | __node_value_type __value_; | <<< our key/value pair - // +-----------------------------+ - // - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( - llvm::StringRef(), - {{"__next_", - ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"__hash_", ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedLongLong)}, - {"__value_", pair_type}}); - std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr); - if (!size) - return false; - WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); - ProcessSP process_sp(target_sp->GetProcessSP()); - Status error; - process_sp->ReadMemory(addr, buffer_sp->GetBytes(), - buffer_sp->GetByteSize(), error); - if (error.Fail()) - return false; - DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - auto pair_sp = CreateValueObjectFromData( - "pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type); - if (pair_sp) - m_pair_sp = pair_sp->GetChildAtIndex(2); - } - - return false; -} - -size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: - CalculateNumChildren() { - return 2; -} - -lldb::ValueObjectSP lldb_private::formatters:: - LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { - if (m_pair_sp) - return m_pair_sp->GetChildAtIndex(idx); - return lldb::ValueObjectSP(); -} - -bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: - MightHaveChildren() { - return true; -} - -size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: - GetIndexOfChildWithName(ConstString name) { - if (name == "first") - return 0; - if (name == "second") - return 1; - return UINT32_MAX; -} - -SyntheticChildrenFrontEnd * -lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator( - CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { - return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp) - : nullptr); -} - -/* (lldb) fr var ibeg --raw --ptr-depth 1 -T (std::__1::__wrap_iter<int *>) ibeg = { (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 { @@ -565,14 +226,14 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: Update(); } -size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return (m_cntrl ? 1 : 0); } lldb::ValueObjectSP lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (!m_cntrl) return lldb::ValueObjectSP(); @@ -600,22 +261,23 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( return lldb::ValueObjectSP(); } -bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { m_cntrl = nullptr; ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; TargetSP target_sp(valobj_sp->GetTargetSP()); if (!target_sp) - return false; + return lldb::ChildCacheState::eRefetch; lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_")); m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular // dependency - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: @@ -659,8 +321,8 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( : nullptr); } -size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxUniquePtrSyntheticFrontEnd::CalculateNumChildren() { if (m_value_ptr_sp) return m_deleter_sp ? 2 : 1; return 0; @@ -668,7 +330,7 @@ size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (!m_value_ptr_sp) return lldb::ValueObjectSP(); @@ -689,14 +351,15 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( return lldb::ValueObjectSP(); } -bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_")); if (!ptr_sp) - return false; + return lldb::ChildCacheState::eRefetch; // Retrieve the actual pointer and the deleter, and clone them to give them // user-friendly names. @@ -708,7 +371,7 @@ bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { if (deleter_sp) m_deleter_sp = deleter_sp->Clone(ConstString("deleter")); - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: @@ -805,6 +468,9 @@ ExtractLibcxxStringInfo(ValueObject &valobj) { size = (layout == StringLayout::DSC) ? size_mode_value : ((size_mode_value >> 1) % 256); + if (!location_sp) + return {}; + // When the small-string optimization takes place, the data must fit in the // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's // likely that the string isn't initialized and we're reading garbage. @@ -812,7 +478,7 @@ ExtractLibcxxStringInfo(ValueObject &valobj) { const std::optional<uint64_t> max_bytes = location_sp->GetCompilerType().GetByteSize( exe_ctx.GetBestExecutionContextScope()); - if (!max_bytes || size > *max_bytes || !location_sp) + if (!max_bytes || size > *max_bytes) return {}; return std::make_pair(size, location_sp); @@ -1084,8 +750,10 @@ bool lldb_private::formatters::LibcxxWStringViewSummaryProvider( dataobj, size); } -bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider( - ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { +static bool +LibcxxChronoTimePointSecondsSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options, + const char *fmt) { ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_"); if (!ptr_sp) return false; @@ -1093,6 +761,7 @@ bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider( if (!ptr_sp) return false; +#ifndef _WIN32 // The date time in the chrono library is valid in the range // [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a // larger range, the function strftime is not able to format the entire range @@ -1102,25 +771,45 @@ bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider( -1'096'193'779'200; // -32767-01-01T00:00:00Z const std::time_t chrono_timestamp_max = 971'890'963'199; // 32767-12-31T23:59:59Z +#else + const std::time_t chrono_timestamp_min = -43'200; // 1969-12-31T12:00:00Z + const std::time_t chrono_timestamp_max = + 32'536'850'399; // 3001-01-19T21:59:59 +#endif const std::time_t seconds = ptr_sp->GetValueAsSigned(0); if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max) - stream.Printf("timestamp=%ld s", seconds); + stream.Printf("timestamp=%" PRId64 " s", static_cast<int64_t>(seconds)); else { std::array<char, 128> str; std::size_t size = - std::strftime(str.data(), str.size(), "%FT%H:%M:%SZ", gmtime(&seconds)); + std::strftime(str.data(), str.size(), fmt, gmtime(&seconds)); if (size == 0) return false; - stream.Printf("date/time=%s timestamp=%ld s", str.data(), seconds); + stream.Printf("date/time=%s timestamp=%" PRId64 " s", str.data(), + static_cast<int64_t>(seconds)); } return true; } -bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider( +bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options, + "%FT%H:%M:%SZ"); +} + +bool lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options, + "%FT%H:%M:%S"); +} + +static bool +LibcxxChronoTimepointDaysSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options, + const char *fmt) { ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_"); if (!ptr_sp) return false; @@ -1128,12 +817,17 @@ bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider( if (!ptr_sp) return false; +#ifndef _WIN32 // The date time in the chrono library is valid in the range // [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the // function strftime is not able to format the entire range of time_t. The // exact point has not been investigated; it's limited to chrono's range. const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z const int chrono_timestamp_max = 11'248'737; // 32767-12-31Z +#else + const int chrono_timestamp_min = 0; // 1970-01-01Z + const int chrono_timestamp_max = 376'583; // 3001-01-19Z +#endif const int days = ptr_sp->GetValueAsSigned(0); if (days < chrono_timestamp_min || days > chrono_timestamp_max) @@ -1144,7 +838,7 @@ bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider( std::array<char, 128> str; std::size_t size = - std::strftime(str.data(), str.size(), "%FZ", gmtime(&seconds)); + std::strftime(str.data(), str.size(), fmt, gmtime(&seconds)); if (size == 0) return false; @@ -1154,6 +848,18 @@ bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options, + "%FZ"); +} + +bool lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options, + "%F"); +} + bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { // FIXME: These are the names used in the C++20 ostream operator. Since LLVM @@ -1188,7 +894,7 @@ bool lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider( return false; const unsigned weekday = ptr_sp->GetValueAsUnsigned(0); - if (weekday >= 0 && weekday < 7) + if (weekday < 7) stream << "weekday=" << weekdays[weekday]; else stream.Printf("weekday=%u", weekday); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 72da6b2426ef..5307b5251ca8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -59,6 +59,10 @@ bool LibcxxWStringViewSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::wstring_view +bool LibcxxStdSliceArraySummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::slice_array + bool LibcxxSmartPointerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions @@ -83,81 +87,6 @@ bool LibcxxContainerSummaryProvider(ValueObject &valobj, Stream &stream, bool LibcxxSpanSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); -class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { -public: - LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - - size_t CalculateNumChildren() override; - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; - - bool Update() override; - - bool MightHaveChildren() override; - - size_t GetIndexOfChildWithName(ConstString name) override; - - ~LibCxxMapIteratorSyntheticFrontEnd() override; - -private: - ValueObject *m_pair_ptr; - lldb::ValueObjectSP m_pair_sp; -}; - -SyntheticChildrenFrontEnd * -LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP); - -/// Formats libcxx's std::unordered_map iterators -/// -/// In raw form a std::unordered_map::iterator is represented as follows: -/// -/// (lldb) var it --raw --ptr-depth 1 -/// (std::__1::__hash_map_iterator< -/// std::__1::__hash_iterator< -/// std::__1::__hash_node< -/// std::__1::__hash_value_type< -/// std::__1::basic_string<char, std::__1::char_traits<char>, -/// std::__1::allocator<char> >, std::__1::basic_string<char, -/// std::__1::char_traits<char>, std::__1::allocator<char> > >, -/// void *> *> >) -/// it = { -/// __i_ = { -/// __node_ = 0x0000600001700040 { -/// __next_ = 0x0000600001704000 -/// } -/// } -/// } -class LibCxxUnorderedMapIteratorSyntheticFrontEnd - : public SyntheticChildrenFrontEnd { -public: - LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - - ~LibCxxUnorderedMapIteratorSyntheticFrontEnd() override = default; - - size_t CalculateNumChildren() override; - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; - - bool Update() override; - - bool MightHaveChildren() override; - - size_t GetIndexOfChildWithName(ConstString name) override; - -private: - ValueObject *m_iter_ptr = nullptr; ///< Held, not owned. Child of iterator - ///< ValueObject supplied at construction. - - lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair - ///< that the iterator currently points - ///< to. -}; - -SyntheticChildrenFrontEnd * -LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, - lldb::ValueObjectSP); - SyntheticChildrenFrontEnd * LibCxxVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -166,11 +95,11 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -186,11 +115,11 @@ class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -220,6 +149,18 @@ LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); SyntheticChildrenFrontEnd * +LibcxxStdValarraySyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * +LibcxxStdSliceArraySyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * +LibcxxStdProxyArraySyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -232,10 +173,18 @@ LibcxxStdMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); SyntheticChildrenFrontEnd * +LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); SyntheticChildrenFrontEnd * +LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + +SyntheticChildrenFrontEnd * LibcxxInitializerListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -269,6 +218,14 @@ bool LibcxxChronoSysDaysSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::chrono::sys_days +bool LibcxxChronoLocalSecondsSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::chrono::local_seconds + +bool LibcxxChronoLocalDaysSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // libc++ std::chrono::local_days + bool LibcxxChronoMonthSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::chrono::month diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp index eacc60886c6e..7f30dc186291 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxAtomic.cpp @@ -90,11 +90,11 @@ public: ~LibcxxStdAtomicSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -110,12 +110,13 @@ lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) : SyntheticChildrenFrontEnd(*valobj_sp) {} -bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::Update() { ValueObjectSP atomic_value = GetLibCxxAtomicValue(m_backend); if (atomic_value) m_real_child = GetLibCxxAtomicValue(m_backend).get(); - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: @@ -123,14 +124,14 @@ bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: return true; } -size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdAtomicSyntheticFrontEnd::CalculateNumChildren() { return m_real_child ? 1 : 0; } lldb::ValueObjectSP lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (idx == 0) return m_real_child->GetSP()->Clone(ConstString("Value")); return nullptr; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp index bfd7b881a728..bd9c72497664 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxInitializerList.cpp @@ -26,11 +26,11 @@ public: ~LibcxxInitializerListSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -59,8 +59,8 @@ lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: // delete m_start; } -size_t lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxInitializerListSyntheticFrontEnd::CalculateNumChildren() { m_num_elements = 0; ValueObjectSP size_sp(m_backend.GetChildMemberWithName("__size_")); if (size_sp) @@ -69,7 +69,7 @@ size_t lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: } lldb::ValueObjectSP lldb_private::formatters:: - LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex(size_t idx) { + LibcxxInitializerListSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (!m_start) return lldb::ValueObjectSP(); @@ -82,13 +82,13 @@ lldb::ValueObjectSP lldb_private::formatters:: m_element_type); } -bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd::Update() { m_start = nullptr; m_num_elements = 0; m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0); if (!m_element_type.IsValid()) - return false; + return lldb::ChildCacheState::eRefetch; if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { m_element_size = *size; @@ -96,7 +96,7 @@ bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: m_start = m_backend.GetChildMemberWithName("__begin_").get(); } - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxInitializerListSyntheticFrontEnd:: diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 2e2e2a8b0515..d7cfeb30557c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -109,7 +109,7 @@ public: return ExtractIndexFromString(name.GetCString()); } bool MightHaveChildren() override { return true; } - bool Update() override; + lldb::ChildCacheState Update() override; protected: AbstractListFrontEnd(ValueObject &valobj) @@ -136,9 +136,9 @@ class ForwardListFrontEnd : public AbstractListFrontEnd { public: ForwardListFrontEnd(ValueObject &valobj); - size_t CalculateNumChildren() override; - ValueObjectSP GetChildAtIndex(size_t idx) override; - bool Update() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; + ValueObjectSP GetChildAtIndex(uint32_t idx) override; + lldb::ChildCacheState Update() override; }; class ListFrontEnd : public AbstractListFrontEnd { @@ -147,11 +147,11 @@ public: ~ListFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; private: lldb::addr_t m_node_address = 0; @@ -160,7 +160,7 @@ private: } // end anonymous namespace -bool AbstractListFrontEnd::Update() { +lldb::ChildCacheState AbstractListFrontEnd::Update() { m_loop_detected = 0; m_count = UINT32_MAX; m_head = nullptr; @@ -180,10 +180,10 @@ bool AbstractListFrontEnd::Update() { list_type = list_type.GetNonReferenceType(); if (list_type.GetNumTemplateArguments() == 0) - return false; + return lldb::ChildCacheState::eRefetch; m_element_type = list_type.GetTypeTemplateArgument(0); - return false; + return lldb::ChildCacheState::eRefetch; } bool AbstractListFrontEnd::HasLoop(size_t count) { @@ -240,7 +240,7 @@ ForwardListFrontEnd::ForwardListFrontEnd(ValueObject &valobj) Update(); } -size_t ForwardListFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> ForwardListFrontEnd::CalculateNumChildren() { if (m_count != UINT32_MAX) return m_count; @@ -253,8 +253,8 @@ size_t ForwardListFrontEnd::CalculateNumChildren() { return m_count; } -ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { - if (idx >= CalculateNumChildren()) +ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(uint32_t idx) { + if (idx >= CalculateNumChildrenIgnoringErrors()) return nullptr; if (!m_head) @@ -284,22 +284,22 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -bool ForwardListFrontEnd::Update() { +lldb::ChildCacheState ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); Status err; ValueObjectSP backend_addr(m_backend.AddressOf(err)); if (err.Fail() || !backend_addr) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__before_begin_")); if (!impl_sp) - return false; + return lldb::ChildCacheState::eRefetch; impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_head = impl_sp->GetChildMemberWithName("__next_").get(); - return false; + return lldb::ChildCacheState::eRefetch; } ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp) @@ -308,7 +308,7 @@ ListFrontEnd::ListFrontEnd(lldb::ValueObjectSP valobj_sp) Update(); } -size_t ListFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> ListFrontEnd::CalculateNumChildren() { if (m_count != UINT32_MAX) return m_count; if (!m_head || !m_tail || m_node_address == 0) @@ -343,11 +343,11 @@ size_t ListFrontEnd::CalculateNumChildren() { } } -lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(size_t idx) { +lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(uint32_t idx) { static ConstString g_value("__value_"); static ConstString g_next("__next_"); - if (idx >= CalculateNumChildren()) + if (idx >= CalculateNumChildrenIgnoringErrors()) return lldb::ValueObjectSP(); if (!m_head || !m_tail || m_node_address == 0) @@ -394,7 +394,7 @@ lldb::ValueObjectSP ListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -bool ListFrontEnd::Update() { +lldb::ChildCacheState ListFrontEnd::Update() { AbstractListFrontEnd::Update(); m_tail = nullptr; m_node_address = 0; @@ -402,16 +402,16 @@ bool ListFrontEnd::Update() { Status err; ValueObjectSP backend_addr(m_backend.AddressOf(err)); if (err.Fail() || !backend_addr) - return false; + return lldb::ChildCacheState::eRefetch; m_node_address = backend_addr->GetValueAsUnsigned(0); if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__end_")); if (!impl_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_head = impl_sp->GetChildMemberWithName("__next_").get(); m_tail = impl_sp->GetChildMemberWithName("__prev_").get(); - return false; + return lldb::ChildCacheState::eRefetch; } SyntheticChildrenFrontEnd *formatters::LibcxxStdListSyntheticFrontEndCreator( diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 092a4120376b..5106a63d531f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -17,11 +17,33 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include <cstdint> +#include <locale> +#include <optional> using namespace lldb; using namespace lldb_private; using namespace lldb_private::formatters; +// The flattened layout of the std::__tree_iterator::__ptr_ looks +// as follows: +// +// The following shows the contiguous block of memory: +// +// +-----------------------------+ class __tree_end_node +// __ptr_ | pointer __left_; | +// +-----------------------------+ class __tree_node_base +// | pointer __right_; | +// | __parent_pointer __parent_; | +// | bool __is_black_; | +// +-----------------------------+ class __tree_node +// | __node_value_type __value_; | <<< our key/value pair +// +-----------------------------+ +// +// where __ptr_ has type __iter_pointer. + class MapEntry { public: MapEntry() = default; @@ -30,7 +52,6 @@ public: : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} ValueObjectSP left() const { - static ConstString g_left("__left_"); if (!m_entry_sp) return m_entry_sp; return m_entry_sp->GetSyntheticChildAtOffset( @@ -38,7 +59,6 @@ public: } ValueObjectSP right() const { - static ConstString g_right("__right_"); if (!m_entry_sp) return m_entry_sp; return m_entry_sp->GetSyntheticChildAtOffset( @@ -47,7 +67,6 @@ public: } ValueObjectSP parent() const { - static ConstString g_parent("__parent_"); if (!m_entry_sp) return m_entry_sp; return m_entry_sp->GetSyntheticChildAtOffset( @@ -83,17 +102,10 @@ private: class MapIterator { public: - MapIterator() = default; - MapIterator(MapEntry entry, size_t depth = 0) - : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {} - MapIterator(ValueObjectSP entry, size_t depth = 0) - : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {} - MapIterator(const MapIterator &rhs) - : m_entry(rhs.m_entry), m_max_depth(rhs.m_max_depth), m_error(false) {} MapIterator(ValueObject *entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {} - MapIterator &operator=(const MapIterator &) = default; + MapIterator() = default; ValueObjectSP value() { return m_entry.GetEntry(); } @@ -111,7 +123,9 @@ public: return m_entry.GetEntry(); } -protected: +private: + /// Mimicks libc++'s __tree_next algorithm, which libc++ uses + /// in its __tree_iteartor::operator++. void next() { if (m_entry.null()) return; @@ -136,7 +150,7 @@ protected: m_entry = MapEntry(m_entry.parent()); } -private: + /// Mimicks libc++'s __tree_min algorithm. MapEntry tree_min(MapEntry x) { if (x.null()) return MapEntry(); @@ -177,222 +191,157 @@ public: ~LibcxxStdMapSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; size_t GetIndexOfChildWithName(ConstString name) override; private: - bool GetDataType(); - - void GetValueOffset(const lldb::ValueObjectSP &node); + /// Returns the ValueObject for the __tree_node type that + /// holds the key/value pair of the node at index \ref idx. + /// + /// \param[in] idx The child index that we're looking to get + /// the key/value pair for. + /// + /// \param[in] max_depth The maximum search depth after which + /// we stop trying to find the key/value + /// pair for. + /// + /// \returns On success, returns the ValueObjectSP corresponding + /// to the __tree_node's __value_ member (which holds + /// the key/value pair the formatter wants to display). + /// On failure, will return nullptr. + ValueObjectSP GetKeyValuePair(size_t idx, size_t max_depth); ValueObject *m_tree = nullptr; ValueObject *m_root_node = nullptr; - CompilerType m_element_type; - uint32_t m_skip_size = UINT32_MAX; + CompilerType m_node_ptr_type; size_t m_count = UINT32_MAX; std::map<size_t, MapIterator> m_iterators; }; + +class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibCxxMapIteratorSyntheticFrontEnd() override = default; + +private: + ValueObjectSP m_pair_sp = nullptr; +}; } // namespace formatters } // namespace lldb_private lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: LibcxxStdMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(), m_iterators() { + : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } -size_t lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren() { if (m_count != UINT32_MAX) return m_count; + if (m_tree == nullptr) return 0; - ValueObjectSP m_item(m_tree->GetChildMemberWithName("__pair3_")); - if (!m_item) + + ValueObjectSP size_node(m_tree->GetChildMemberWithName("__pair3_")); + if (!size_node) return 0; - switch (m_item->GetCompilerType().GetNumDirectBaseClasses()) { - case 1: - // Assume a pre llvm r300140 __compressed_pair implementation: - m_item = m_item->GetChildMemberWithName("__first_"); - break; - case 2: { - // Assume a post llvm r300140 __compressed_pair implementation: - ValueObjectSP first_elem_parent = m_item->GetChildAtIndex(0); - m_item = first_elem_parent->GetChildMemberWithName("__value_"); - break; - } - default: - return false; - } + size_node = GetFirstValueOfLibCXXCompressedPair(*size_node); - if (!m_item) + if (!size_node) return 0; - m_count = m_item->GetValueAsUnsigned(0); + + m_count = size_node->GetValueAsUnsigned(0); return m_count; } -bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType() { - if (m_element_type.IsValid()) - return true; - m_element_type.Clear(); - ValueObjectSP deref; - Status error; - deref = m_root_node->Dereference(error); - if (!deref || error.Fail()) - return false; - deref = deref->GetChildMemberWithName("__value_"); - if (deref) { - m_element_type = deref->GetCompilerType(); - return true; - } - deref = m_backend.GetChildAtNamePath({"__tree_", "__pair3_"}); - if (!deref) - return false; - m_element_type = deref->GetCompilerType() - .GetTypeTemplateArgument(1) - .GetTypeTemplateArgument(1); - if (m_element_type) { - std::string name; - uint64_t bit_offset_ptr; - uint32_t bitfield_bit_size_ptr; - bool is_bitfield_ptr; - m_element_type = m_element_type.GetFieldAtIndex( - 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr); - m_element_type = m_element_type.GetTypedefedType(); - return m_element_type.IsValid(); - } else { - m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0); - return m_element_type.IsValid(); - } -} +ValueObjectSP +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetKeyValuePair( + size_t idx, size_t max_depth) { + MapIterator iterator(m_root_node, max_depth); -void lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset( - const lldb::ValueObjectSP &node) { - if (m_skip_size != UINT32_MAX) - return; - if (!node) - return; - CompilerType node_type(node->GetCompilerType()); - uint64_t bit_offset; - if (node_type.GetIndexOfFieldWithName("__value_", nullptr, &bit_offset) != - UINT32_MAX) { - m_skip_size = bit_offset / 8u; - } else { - auto ast_ctx = node_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>(); - if (!ast_ctx) - return; - CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier( - llvm::StringRef(), - {{"ptr0", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr1", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"ptr2", ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()}, - {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)}, - {"payload", (m_element_type.GetCompleteType(), m_element_type)}}); - std::string child_name; - uint32_t child_byte_size; - int32_t child_byte_offset = 0; - uint32_t child_bitfield_bit_size; - uint32_t child_bitfield_bit_offset; - bool child_is_base_class; - bool child_is_deref_of_parent; - uint64_t language_flags; - if (tree_node_type - .GetChildCompilerTypeAtIndex( - nullptr, 4, true, true, true, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, - child_bitfield_bit_offset, child_is_base_class, - child_is_deref_of_parent, nullptr, language_flags) - .IsValid()) - m_skip_size = (uint32_t)child_byte_offset; + size_t advance_by = idx; + if (idx > 0) { + // If we have already created the iterator for the previous + // index, we can start from there and advance by 1. + auto cached_iterator = m_iterators.find(idx - 1); + if (cached_iterator != m_iterators.end()) { + iterator = cached_iterator->second; + advance_by = 1; + } } + + ValueObjectSP iterated_sp(iterator.advance(advance_by)); + if (!iterated_sp) + // this tree is garbage - stop + return nullptr; + + if (!m_node_ptr_type.IsValid()) + return nullptr; + + // iterated_sp is a __iter_pointer at this point. + // We can cast it to a __node_pointer (which is what libc++ does). + auto value_type_sp = iterated_sp->Cast(m_node_ptr_type); + if (!value_type_sp) + return nullptr; + + // Finally, get the key/value pair. + value_type_sp = value_type_sp->GetChildMemberWithName("__value_"); + if (!value_type_sp) + return nullptr; + + m_iterators[idx] = iterator; + + return value_type_sp; } lldb::ValueObjectSP lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { static ConstString g_cc_("__cc_"), g_cc("__cc"); static ConstString g_nc("__nc"); + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); + if (idx >= num_children) + return nullptr; - if (idx >= CalculateNumChildren()) - return lldb::ValueObjectSP(); if (m_tree == nullptr || m_root_node == nullptr) - return lldb::ValueObjectSP(); + return nullptr; - MapIterator iterator(m_root_node, CalculateNumChildren()); - - const bool need_to_skip = (idx > 0); - size_t actual_advancde = idx; - if (need_to_skip) { - auto cached_iterator = m_iterators.find(idx - 1); - if (cached_iterator != m_iterators.end()) { - iterator = cached_iterator->second; - actual_advancde = 1; - } - } - - ValueObjectSP iterated_sp(iterator.advance(actual_advancde)); - if (!iterated_sp) { - // this tree is garbage - stop - m_tree = - nullptr; // this will stop all future searches until an Update() happens - return iterated_sp; - } - if (GetDataType()) { - if (!need_to_skip) { - Status error; - iterated_sp = iterated_sp->Dereference(error); - if (!iterated_sp || error.Fail()) { - m_tree = nullptr; - return lldb::ValueObjectSP(); - } - GetValueOffset(iterated_sp); - auto child_sp = iterated_sp->GetChildMemberWithName("__value_"); - if (child_sp) - iterated_sp = child_sp; - else - iterated_sp = iterated_sp->GetSyntheticChildAtOffset( - m_skip_size, m_element_type, true); - if (!iterated_sp) { - m_tree = nullptr; - return lldb::ValueObjectSP(); - } - } else { - // because of the way our debug info is made, we need to read item 0 - // first so that we can cache information used to generate other elements - if (m_skip_size == UINT32_MAX) - GetChildAtIndex(0); - if (m_skip_size == UINT32_MAX) { - m_tree = nullptr; - return lldb::ValueObjectSP(); - } - iterated_sp = iterated_sp->GetSyntheticChildAtOffset( - m_skip_size, m_element_type, true); - if (!iterated_sp) { - m_tree = nullptr; - return lldb::ValueObjectSP(); - } - } - } else { + ValueObjectSP key_val_sp = GetKeyValuePair(idx, /*max_depth=*/num_children); + if (!key_val_sp) { + // this will stop all future searches until an Update() happens m_tree = nullptr; - return lldb::ValueObjectSP(); + return nullptr; } + // at this point we have a valid // we need to copy current_sp into a new object otherwise we will end up with // all items named __value_ StreamString name; name.Printf("[%" PRIu64 "]", (uint64_t)idx); - auto potential_child_sp = iterated_sp->Clone(ConstString(name.GetString())); + auto potential_child_sp = key_val_sp->Clone(ConstString(name.GetString())); if (potential_child_sp) { - switch (potential_child_sp->GetNumChildren()) { + switch (potential_child_sp->GetNumChildrenIgnoringErrors()) { case 1: { auto child0_sp = potential_child_sp->GetChildAtIndex(0); if (child0_sp && @@ -411,19 +360,22 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex( } } } - m_iterators[idx] = iterator; return potential_child_sp; } -bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update() { m_count = UINT32_MAX; m_tree = m_root_node = nullptr; m_iterators.clear(); m_tree = m_backend.GetChildMemberWithName("__tree_").get(); if (!m_tree) - return false; + return lldb::ChildCacheState::eRefetch; m_root_node = m_tree->GetChildMemberWithName("__begin_node_").get(); - return false; + m_node_ptr_type = + m_tree->GetCompilerType().GetDirectNestedTypeWithName("__node_pointer"); + + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd:: @@ -441,3 +393,107 @@ lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator( CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { return (valobj_sp ? new LibcxxStdMapSyntheticFrontEnd(valobj_sp) : nullptr); } + +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +lldb::ChildCacheState +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() { + m_pair_sp.reset(); + + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ChildCacheState::eRefetch; + + TargetSP target_sp(valobj_sp->GetTargetSP()); + if (!target_sp) + return lldb::ChildCacheState::eRefetch; + + // m_backend is a std::map::iterator + // ...which is a __map_iterator<__tree_iterator<..., __node_pointer, ...>> + // + // Then, __map_iterator::__i_ is a __tree_iterator + auto tree_iter_sp = valobj_sp->GetChildMemberWithName("__i_"); + if (!tree_iter_sp) + return lldb::ChildCacheState::eRefetch; + + // Type is __tree_iterator::__node_pointer + // (We could alternatively also get this from the template argument) + auto node_pointer_type = + tree_iter_sp->GetCompilerType().GetDirectNestedTypeWithName( + "__node_pointer"); + if (!node_pointer_type.IsValid()) + return lldb::ChildCacheState::eRefetch; + + // __ptr_ is a __tree_iterator::__iter_pointer + auto iter_pointer_sp = tree_iter_sp->GetChildMemberWithName("__ptr_"); + if (!iter_pointer_sp) + return lldb::ChildCacheState::eRefetch; + + // Cast the __iter_pointer to a __node_pointer (which stores our key/value + // pair) + auto node_pointer_sp = iter_pointer_sp->Cast(node_pointer_type); + if (!node_pointer_sp) + return lldb::ChildCacheState::eRefetch; + + auto key_value_sp = node_pointer_sp->GetChildMemberWithName("__value_"); + if (!key_value_sp) + return lldb::ChildCacheState::eRefetch; + + // Create the synthetic child, which is a pair where the key and value can be + // retrieved by querying the synthetic frontend for + // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second") + // respectively. + // + // std::map stores the actual key/value pair in value_type::__cc_ (or + // previously __cc). + key_value_sp = key_value_sp->Clone(ConstString("pair")); + if (key_value_sp->GetNumChildrenIgnoringErrors() == 1) { + auto child0_sp = key_value_sp->GetChildAtIndex(0); + if (child0_sp && + (child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc")) + key_value_sp = child0_sp->Clone(ConstString("pair")); + } + + m_pair_sp = key_value_sp; + + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren() { + return 2; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_pair_sp) + return nullptr; + + return m_pair_sp->GetChildAtIndex(idx); +} + +bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_pair_sp) + return UINT32_MAX; + + return m_pair_sp->GetIndexOfChildWithName(name); +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp) + : nullptr); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp new file mode 100644 index 000000000000..726f06523b97 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxProxyArray.cpp @@ -0,0 +1,194 @@ +//===-- LibCxxProxyArray.cpp-----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { +namespace formatters { + +/// Data formatter for libc++'s std::"proxy_array". +/// +/// A proxy_array's are created by using: +/// std::gslice_array operator[](const std::gslice& gslicearr); +/// std::mask_array operator[](const std::valarray<bool>& boolarr); +/// std::indirect_array operator[](const std::valarray<std::size_t>& indarr); +/// +/// These arrays have the following members: +/// - __vp_ points to std::valarray::__begin_ +/// - __1d_ an array of offsets of the elements from @a __vp_ +class LibcxxStdProxyArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~LibcxxStdProxyArraySyntheticFrontEnd() override; + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + /// A non-owning pointer to the array's __vp_. + ValueObject *m_base = nullptr; + /// The type of the array's template argument T. + CompilerType m_element_type; + /// The sizeof the array's template argument T. + uint32_t m_element_size = 0; + + /// A non-owning pointer to the array's __1d_.__begin_. + ValueObject *m_start = nullptr; + /// A non-owning pointer to the array's __1d_.__end_. + ValueObject *m_finish = nullptr; + /// The type of the __1d_ array's template argument T (size_t). + CompilerType m_element_type_size_t; + /// The sizeof the __1d_ array's template argument T (size_t) + uint32_t m_element_size_size_t = 0; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: + LibcxxStdProxyArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: + ~LibcxxStdProxyArraySyntheticFrontEnd() { + // these need to stay around because they are child objects who will follow + // their parent's life cycle + // delete m_base; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdProxyArraySyntheticFrontEnd::CalculateNumChildren() { + + if (!m_start || !m_finish) + return 0; + uint64_t start_val = m_start->GetValueAsUnsigned(0); + uint64_t finish_val = m_finish->GetValueAsUnsigned(0); + + if (start_val == 0 || finish_val == 0) + return 0; + + if (start_val >= finish_val) + return 0; + + size_t num_children = (finish_val - start_val); + if (num_children % m_element_size_size_t) + return 0; + return num_children / m_element_size_size_t; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_base) + return lldb::ValueObjectSP(); + + uint64_t offset = idx * m_element_size_size_t; + offset = offset + m_start->GetValueAsUnsigned(0); + + lldb::ValueObjectSP indirect = CreateValueObjectFromAddress( + "", offset, m_backend.GetExecutionContextRef(), m_element_type_size_t); + if (!indirect) + return lldb::ValueObjectSP(); + + const size_t value = indirect->GetValueAsUnsigned(0); + if (!value) + return lldb::ValueObjectSP(); + + offset = value * m_element_size; + offset = offset + m_base->GetValueAsUnsigned(0); + + StreamString name; + name.Printf("[%" PRIu64 "] -> [%zu]", (uint64_t)idx, value); + return CreateValueObjectFromAddress(name.GetString(), offset, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd::Update() { + m_base = nullptr; + m_start = nullptr; + m_finish = nullptr; + + CompilerType type = m_backend.GetCompilerType(); + if (type.GetNumTemplateArguments() == 0) + return ChildCacheState::eRefetch; + + m_element_type = type.GetTypeTemplateArgument(0); + if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) + m_element_size = *size; + + if (m_element_size == 0) + return ChildCacheState::eRefetch; + + ValueObjectSP vector = m_backend.GetChildMemberWithName("__1d_"); + if (!vector) + return ChildCacheState::eRefetch; + + type = vector->GetCompilerType(); + if (type.GetNumTemplateArguments() == 0) + return ChildCacheState::eRefetch; + + m_element_type_size_t = type.GetTypeTemplateArgument(0); + if (std::optional<uint64_t> size = m_element_type_size_t.GetByteSize(nullptr)) + m_element_size_size_t = *size; + + if (m_element_size_size_t == 0) + return ChildCacheState::eRefetch; + + ValueObjectSP base = m_backend.GetChildMemberWithName("__vp_"); + ValueObjectSP start = vector->GetChildMemberWithName("__begin_"); + ValueObjectSP finish = vector->GetChildMemberWithName("__end_"); + if (!base || !start || !finish) + return ChildCacheState::eRefetch; + + m_base = base.get(); + m_start = start.get(); + m_finish = finish.get(); + + return ChildCacheState::eRefetch; +} + +bool lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_base) + return std::numeric_limits<size_t>::max(); + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxStdProxyArraySyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + return new LibcxxStdProxyArraySyntheticFrontEnd(valobj_sp); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp index c31940af0881..5b459a17fe29 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxQueue.cpp @@ -26,13 +26,13 @@ public: } bool MightHaveChildren() override { return true; } - bool Update() override; + lldb::ChildCacheState Update() override; - size_t CalculateNumChildren() override { + llvm::Expected<uint32_t> CalculateNumChildren() override { return m_container_sp ? m_container_sp->GetNumChildren() : 0; } - ValueObjectSP GetChildAtIndex(size_t idx) override { + ValueObjectSP GetChildAtIndex(uint32_t idx) override { return m_container_sp ? m_container_sp->GetChildAtIndex(idx) : nullptr; } @@ -47,13 +47,13 @@ private: }; } // namespace -bool QueueFrontEnd::Update() { +lldb::ChildCacheState QueueFrontEnd::Update() { m_container_sp = nullptr; ValueObjectSP c_sp = m_backend.GetChildMemberWithName("c"); if (!c_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_container_sp = c_sp->GetSyntheticValue().get(); - return false; + return lldb::ChildCacheState::eRefetch; } SyntheticChildrenFrontEnd * diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp index 6aeb557a95ff..01a7b8f142ec 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxRangesRefView.cpp @@ -27,18 +27,18 @@ public: ~LibcxxStdRangesRefViewSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override { + llvm::Expected<uint32_t> CalculateNumChildren() override { // __range_ will be the sole child of this type return 1; } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { // Since we only have a single child, return it assert(idx == 0); return m_range_sp; } - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override { return true; } @@ -59,17 +59,18 @@ lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEnd:: Update(); } -bool lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEnd:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdRangesRefViewSyntheticFrontEnd::Update() { ValueObjectSP range_ptr = GetChildMemberWithName(m_backend, {ConstString("__range_")}); if (!range_ptr) - return false; + return lldb::ChildCacheState::eRefetch; lldb_private::Status error; m_range_sp = range_ptr->Dereference(error); - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } lldb_private::SyntheticChildrenFrontEnd * diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp new file mode 100644 index 000000000000..c33d8e91af70 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSliceArray.cpp @@ -0,0 +1,166 @@ +//===-- LibCxxSliceArray.cpp-----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { +namespace formatters { + +bool LibcxxStdSliceArraySummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options) { + ValueObjectSP obj = valobj.GetNonSyntheticValue(); + if (!obj) + return false; + + ValueObjectSP ptr_sp = obj->GetChildMemberWithName("__size_"); + if (!ptr_sp) + return false; + const size_t size = ptr_sp->GetValueAsUnsigned(0); + + ptr_sp = obj->GetChildMemberWithName("__stride_"); + if (!ptr_sp) + return false; + const size_t stride = ptr_sp->GetValueAsUnsigned(0); + + stream.Printf("stride=%zu size=%zu", stride, size); + + return true; +} + +/// Data formatter for libc++'s std::slice_array. +/// +/// A slice_array is created by using: +/// operator[](std::slice slicearr); +/// and std::slice is created by: +/// slice(std::size_t start, std::size_t size, std::size_t stride); +/// The std::slice_array has the following members: +/// - __vp_ points to std::valarray::__begin_ + @a start +/// - __size_ is @a size +/// - __stride_is @a stride +class LibcxxStdSliceArraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~LibcxxStdSliceArraySyntheticFrontEnd() override; + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + /// A non-owning pointer to slice_array.__vp_. + ValueObject *m_start = nullptr; + /// slice_array.__size_. + size_t m_size = 0; + /// slice_array.__stride_. + size_t m_stride = 0; + /// The type of slice_array's template argument T. + CompilerType m_element_type; + /// The sizeof slice_array's template argument T. + uint32_t m_element_size = 0; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: + LibcxxStdSliceArraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: + ~LibcxxStdSliceArraySyntheticFrontEnd() { + // these need to stay around because they are child objects who will follow + // their parent's life cycle + // delete m_start; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdSliceArraySyntheticFrontEnd::CalculateNumChildren() { + return m_size; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_start) + return lldb::ValueObjectSP(); + + uint64_t offset = idx * m_stride * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(name.GetString(), offset, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd::Update() { + m_start = nullptr; + + CompilerType type = m_backend.GetCompilerType(); + if (type.GetNumTemplateArguments() == 0) + return ChildCacheState::eRefetch; + + m_element_type = type.GetTypeTemplateArgument(0); + if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) + m_element_size = *size; + + if (m_element_size == 0) + return ChildCacheState::eRefetch; + + ValueObjectSP start = m_backend.GetChildMemberWithName("__vp_"); + ValueObjectSP size = m_backend.GetChildMemberWithName("__size_"); + ValueObjectSP stride = m_backend.GetChildMemberWithName("__stride_"); + + if (!start || !size || !stride) + return ChildCacheState::eRefetch; + + m_start = start.get(); + m_size = size->GetValueAsUnsigned(0); + m_stride = stride->GetValueAsUnsigned(0); + + return ChildCacheState::eRefetch; +} + +bool lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_start) + return std::numeric_limits<size_t>::max(); + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxStdSliceArraySyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + return new LibcxxStdSliceArraySyntheticFrontEnd(valobj_sp); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp index ec062ed21ee4..9895f336bfd0 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxSpan.cpp @@ -27,9 +27,9 @@ public: ~LibcxxStdSpanSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; /// Determines properties of the std::span<> associated with this object // @@ -53,7 +53,7 @@ public: // This function checks for a '__size' member to determine the number // of elements in the span. If no such member exists, we get the size // from the only other place it can be: the template argument. - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -73,14 +73,14 @@ lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: Update(); } -size_t lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdSpanSyntheticFrontEnd::CalculateNumChildren() { return m_num_elements; } lldb::ValueObjectSP lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (!m_start) return {}; @@ -93,12 +93,13 @@ lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::GetChildAtIndex( m_element_type); } -bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { // Get element type. ValueObjectSP data_type_finder_sp = GetChildMemberWithName( m_backend, {ConstString("__data_"), ConstString("__data")}); if (!data_type_finder_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); @@ -122,7 +123,7 @@ bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd::Update() { } } - return true; + return lldb::ChildCacheState::eReuse; } bool lldb_private::formatters::LibcxxStdSpanSyntheticFrontEnd:: diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp index 9024ed4dba45..3e3259ab428d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxTuple.cpp @@ -25,9 +25,11 @@ public: } bool MightHaveChildren() override { return true; } - bool Update() override; - size_t CalculateNumChildren() override { return m_elements.size(); } - ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ChildCacheState Update() override; + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_elements.size(); + } + ValueObjectSP GetChildAtIndex(uint32_t idx) override; private: // The lifetime of a ValueObject and all its derivative ValueObjects @@ -40,7 +42,7 @@ private: }; } -bool TupleFrontEnd::Update() { +lldb::ChildCacheState TupleFrontEnd::Update() { m_elements.clear(); m_base = nullptr; @@ -51,14 +53,14 @@ bool TupleFrontEnd::Update() { base_sp = m_backend.GetChildMemberWithName("base_"); } if (!base_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_base = base_sp.get(); m_elements.assign(base_sp->GetCompilerType().GetNumDirectBaseClasses(), nullptr); - return false; + return lldb::ChildCacheState::eRefetch; } -ValueObjectSP TupleFrontEnd::GetChildAtIndex(size_t idx) { +ValueObjectSP TupleFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx >= m_elements.size()) return ValueObjectSP(); if (!m_base) diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index ff7043bdf97f..93e7f4f4fd86 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -33,11 +33,11 @@ public: ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -51,6 +51,30 @@ private: ValueObject *m_next_element = nullptr; std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache; }; + +class LibCxxUnorderedMapIteratorSyntheticFrontEnd + : public SyntheticChildrenFrontEnd { +public: + LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~LibCxxUnorderedMapIteratorSyntheticFrontEnd() override = default; + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair + ///< that the iterator currently points + ///< to. +}; + } // namespace formatters } // namespace lldb_private @@ -62,8 +86,8 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: Update(); } -size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdUnorderedMapSyntheticFrontEnd::CalculateNumChildren() { return m_num_elements; } @@ -93,8 +117,8 @@ static bool isUnorderedMap(ConstString type_name) { } lldb::ValueObjectSP lldb_private::formatters:: - LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) { - if (idx >= CalculateNumChildren()) + LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { + if (idx >= CalculateNumChildrenIgnoringErrors()) return lldb::ValueObjectSP(); if (m_tree == nullptr) return lldb::ValueObjectSP(); @@ -116,25 +140,10 @@ lldb::ValueObjectSP lldb_private::formatters:: if (!p1_sp) return nullptr; - ValueObjectSP first_sp = nullptr; - switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) { - case 1: - // Assume a pre llvm r300140 __compressed_pair implementation: - first_sp = p1_sp->GetChildMemberWithName("__first_"); - break; - case 2: { - // Assume a post llvm r300140 __compressed_pair implementation: - ValueObjectSP first_elem_parent_sp = - p1_sp->GetChildAtIndex(0); - first_sp = p1_sp->GetChildMemberWithName("__value_"); - break; - } - default: - return nullptr; - } - + ValueObjectSP first_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); if (!first_sp) return nullptr; + m_element_type = first_sp->GetCompilerType(); m_element_type = m_element_type.GetTypeTemplateArgument(0); m_element_type = m_element_type.GetPointeeType(); @@ -208,48 +217,41 @@ lldb::ValueObjectSP lldb_private::formatters:: m_element_type); } -bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::Update() { m_num_elements = 0; m_next_element = nullptr; m_elements_cache.clear(); ValueObjectSP table_sp = m_backend.GetChildMemberWithName("__table_"); if (!table_sp) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP p2_sp = table_sp->GetChildMemberWithName("__p2_"); - ValueObjectSP num_elements_sp = nullptr; - llvm::SmallVector<llvm::StringRef, 3> next_path; - switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) { - case 1: - // Assume a pre llvm r300140 __compressed_pair implementation: - num_elements_sp = p2_sp->GetChildMemberWithName("__first_"); - next_path.append({"__p1_", "__first_", "__next_"}); - break; - case 2: { - // Assume a post llvm r300140 __compressed_pair implementation: - ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0); - num_elements_sp = first_elem_parent->GetChildMemberWithName("__value_"); - next_path.append({"__p1_", "__value_", "__next_"}); - break; - } - default: - return false; - } + if (!p2_sp) + return lldb::ChildCacheState::eRefetch; + ValueObjectSP num_elements_sp = GetFirstValueOfLibCXXCompressedPair(*p2_sp); if (!num_elements_sp) - return false; + return lldb::ChildCacheState::eRefetch; + + ValueObjectSP p1_sp = table_sp->GetChildMemberWithName("__p1_"); + if (!p1_sp) + return lldb::ChildCacheState::eRefetch; + + ValueObjectSP value_sp = GetFirstValueOfLibCXXCompressedPair(*p1_sp); + if (!value_sp) + return lldb::ChildCacheState::eRefetch; - m_tree = table_sp->GetChildAtNamePath(next_path).get(); + m_tree = value_sp->GetChildMemberWithName("__next_").get(); if (m_tree == nullptr) - return false; + return lldb::ChildCacheState::eRefetch; m_num_elements = num_elements_sp->GetValueAsUnsigned(0); if (m_num_elements > 0) - m_next_element = - table_sp->GetChildAtNamePath(next_path).get(); - return false; + m_next_element = m_tree; + + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd:: @@ -268,3 +270,119 @@ lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator( return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp) : nullptr); } + +lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: + LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +lldb::ChildCacheState lldb_private::formatters:: + LibCxxUnorderedMapIteratorSyntheticFrontEnd::Update() { + m_pair_sp.reset(); + + ValueObjectSP valobj_sp = m_backend.GetSP(); + if (!valobj_sp) + return lldb::ChildCacheState::eRefetch; + + TargetSP target_sp(valobj_sp->GetTargetSP()); + + if (!target_sp) + return lldb::ChildCacheState::eRefetch; + + // Get the unordered_map::iterator + // m_backend is an 'unordered_map::iterator', aka a + // '__hash_map_iterator<__hash_table::iterator>' + // + // __hash_map_iterator::__i_ is a __hash_table::iterator (aka + // __hash_iterator<__node_pointer>) + auto hash_iter_sp = valobj_sp->GetChildMemberWithName("__i_"); + if (!hash_iter_sp) + return lldb::ChildCacheState::eRefetch; + + // Type is '__hash_iterator<__node_pointer>' + auto hash_iter_type = hash_iter_sp->GetCompilerType(); + if (!hash_iter_type.IsValid()) + return lldb::ChildCacheState::eRefetch; + + // Type is '__node_pointer' + auto node_pointer_type = hash_iter_type.GetTypeTemplateArgument(0); + if (!node_pointer_type.IsValid()) + return lldb::ChildCacheState::eRefetch; + + // Cast the __hash_iterator to a __node_pointer (which stores our key/value + // pair) + auto hash_node_sp = hash_iter_sp->Cast(node_pointer_type); + if (!hash_node_sp) + return lldb::ChildCacheState::eRefetch; + + auto key_value_sp = hash_node_sp->GetChildMemberWithName("__value_"); + if (!key_value_sp) { + // clang-format off + // Since D101206 (ba79fb2e1f), libc++ wraps the `__value_` in an + // anonymous union. + // Child 0: __hash_node_base base class + // Child 1: __hash_ + // Child 2: anonymous union + // clang-format on + auto anon_union_sp = hash_node_sp->GetChildAtIndex(2); + if (!anon_union_sp) + return lldb::ChildCacheState::eRefetch; + + key_value_sp = anon_union_sp->GetChildMemberWithName("__value_"); + if (!key_value_sp) + return lldb::ChildCacheState::eRefetch; + } + + // Create the synthetic child, which is a pair where the key and value can be + // retrieved by querying the synthetic frontend for + // GetIndexOfChildWithName("first") and GetIndexOfChildWithName("second") + // respectively. + // + // std::unordered_map stores the actual key/value pair in + // __hash_value_type::__cc_ (or previously __cc). + auto potential_child_sp = key_value_sp->Clone(ConstString("pair")); + if (potential_child_sp) + if (potential_child_sp->GetNumChildrenIgnoringErrors() == 1) + if (auto child0_sp = potential_child_sp->GetChildAtIndex(0); + child0_sp->GetName() == "__cc_" || child0_sp->GetName() == "__cc") + potential_child_sp = child0_sp->Clone(ConstString("pair")); + + m_pair_sp = potential_child_sp; + + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibCxxUnorderedMapIteratorSyntheticFrontEnd::CalculateNumChildren() { + return 2; +} + +lldb::ValueObjectSP lldb_private::formatters:: + LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { + if (m_pair_sp) + return m_pair_sp->GetChildAtIndex(idx); + return lldb::ValueObjectSP(); +} + +bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "first") + return 0; + if (name == "second") + return 1; + return UINT32_MAX; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp) + : nullptr); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp new file mode 100644 index 000000000000..99f94406e99a --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp @@ -0,0 +1,145 @@ +//===-- LibCxxValarray.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { +namespace formatters { +class LibcxxStdValarraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~LibcxxStdValarraySyntheticFrontEnd() override; + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + /// A non-owning pointer to valarray's __begin_ member. + ValueObject *m_start = nullptr; + /// A non-owning pointer to valarray's __end_ member. + ValueObject *m_finish = nullptr; + /// The type of valarray's template argument T. + CompilerType m_element_type; + /// The sizeof valarray's template argument T. + uint32_t m_element_size = 0; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + ~LibcxxStdValarraySyntheticFrontEnd() { + // these need to stay around because they are child objects who will follow + // their parent's life cycle + // delete m_start; + // delete m_finish; +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdValarraySyntheticFrontEnd::CalculateNumChildren() { + if (!m_start || !m_finish) + return 0; + uint64_t start_val = m_start->GetValueAsUnsigned(0); + uint64_t finish_val = m_finish->GetValueAsUnsigned(0); + + if (start_val == 0 || finish_val == 0) + return 0; + + if (start_val >= finish_val) + return 0; + + size_t num_children = (finish_val - start_val); + if (num_children % m_element_size) + return 0; + return num_children / m_element_size; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (!m_start || !m_finish) + return lldb::ValueObjectSP(); + + uint64_t offset = idx * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(name.GetString(), offset, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::Update() { + m_start = m_finish = nullptr; + + CompilerType type = m_backend.GetCompilerType(); + if (type.GetNumTemplateArguments() == 0) + return ChildCacheState::eRefetch; + + m_element_type = type.GetTypeTemplateArgument(0); + if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) + m_element_size = *size; + + if (m_element_size == 0) + return ChildCacheState::eRefetch; + + ValueObjectSP start = m_backend.GetChildMemberWithName("__begin_"); + ValueObjectSP finish = m_backend.GetChildMemberWithName("__end_"); + + if (!start || !finish) + return ChildCacheState::eRefetch; + + m_start = start.get(); + m_finish = finish.get(); + + return ChildCacheState::eRefetch; +} + +bool lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_start || !m_finish) + return std::numeric_limits<size_t>::max(); + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + return new LibcxxStdValarraySyntheticFrontEnd(valobj_sp); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp index e863ccca2be8..62794318e077 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp @@ -204,36 +204,36 @@ public: } bool MightHaveChildren() override { return true; } - bool Update() override; - size_t CalculateNumChildren() override { return m_size; } - ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ChildCacheState Update() override; + llvm::Expected<uint32_t> CalculateNumChildren() override { return m_size; } + ValueObjectSP GetChildAtIndex(uint32_t idx) override; private: size_t m_size = 0; }; } // namespace -bool VariantFrontEnd::Update() { +lldb::ChildCacheState VariantFrontEnd::Update() { m_size = 0; ValueObjectSP impl_sp = formatters::GetChildMemberWithName( m_backend, {ConstString("__impl_"), ConstString("__impl")}); if (!impl_sp) - return false; + return lldb::ChildCacheState::eRefetch; LibcxxVariantIndexValidity validity = LibcxxVariantGetIndexValidity(impl_sp); if (validity == LibcxxVariantIndexValidity::Invalid) - return false; + return lldb::ChildCacheState::eRefetch; if (validity == LibcxxVariantIndexValidity::NPos) - return true; + return lldb::ChildCacheState::eReuse; m_size = 1; - return false; + return lldb::ChildCacheState::eRefetch; } -ValueObjectSP VariantFrontEnd::GetChildAtIndex(size_t idx) { +ValueObjectSP VariantFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx >= m_size) return {}; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp index db7cc5bce26e..461fed35164b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxxVector.cpp @@ -25,11 +25,11 @@ public: ~LibcxxStdVectorSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -46,11 +46,11 @@ class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override { return true; } @@ -82,8 +82,8 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: // delete m_finish; } -size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren() { if (!m_start || !m_finish) return 0; uint64_t start_val = m_start->GetValueAsUnsigned(0); @@ -103,7 +103,7 @@ size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (!m_start || !m_finish) return lldb::ValueObjectSP(); @@ -116,33 +116,19 @@ lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex( m_element_type); } -bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { m_start = m_finish = nullptr; ValueObjectSP data_type_finder_sp( m_backend.GetChildMemberWithName("__end_cap_")); if (!data_type_finder_sp) - return false; - - switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) { - case 1: - // Assume a pre llvm r300140 __compressed_pair implementation: - data_type_finder_sp = - data_type_finder_sp->GetChildMemberWithName("__first_"); - break; - case 2: { - // Assume a post llvm r300140 __compressed_pair implementation: - ValueObjectSP first_elem_parent_sp = - data_type_finder_sp->GetChildAtIndex(0); - data_type_finder_sp = - first_elem_parent_sp->GetChildMemberWithName("__value_"); - break; - } - default: - return false; - } + return lldb::ChildCacheState::eRefetch; + data_type_finder_sp = + GetFirstValueOfLibCXXCompressedPair(*data_type_finder_sp); if (!data_type_finder_sp) - return false; + return lldb::ChildCacheState::eRefetch; + m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); if (std::optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { m_element_size = *size; @@ -153,7 +139,7 @@ bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { m_finish = m_backend.GetChildMemberWithName("__end_").get(); } } - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: @@ -179,14 +165,14 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: } } -size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren() { return m_count; } lldb::ValueObjectSP lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { auto iter = m_children.find(idx), end = m_children.end(); if (iter != end) return iter->second; @@ -241,29 +227,30 @@ lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( } }*/ -bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName("__size_")); if (!size_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_count = size_sp->GetValueAsUnsigned(0); if (!m_count) - return true; + return lldb::ChildCacheState::eReuse; ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName("__begin_")); if (!begin_sp) { m_count = 0; - return false; + return lldb::ChildCacheState::eRefetch; } m_base_data_address = begin_sp->GetValueAsUnsigned(0); if (!m_base_data_address) { m_count = 0; - return false; + return lldb::ChildCacheState::eRefetch; } - return false; + return lldb::ChildCacheState::eRefetch; } size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: @@ -272,7 +259,7 @@ size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: return UINT32_MAX; const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 23af50fdb712..86bb575af5ca 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -43,11 +43,11 @@ class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -64,11 +64,11 @@ class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -94,29 +94,29 @@ LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd( Update(); } -bool LibstdcppMapIteratorSyntheticFrontEnd::Update() { +lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; TargetSP target_sp(valobj_sp->GetTargetSP()); if (!target_sp) - return false; + return lldb::ChildCacheState::eRefetch; bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node")); if (!_M_node_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_pair_address = _M_node_sp->GetValueAsUnsigned(0); if (m_pair_address == 0) - return false; + return lldb::ChildCacheState::eRefetch; m_pair_address += (is_64bit ? 32 : 16); @@ -124,20 +124,21 @@ bool LibstdcppMapIteratorSyntheticFrontEnd::Update() { if (my_type.GetNumTemplateArguments() >= 1) { CompilerType pair_type = my_type.GetTypeTemplateArgument(0); if (!pair_type) - return false; + return lldb::ChildCacheState::eRefetch; m_pair_type = pair_type; } else - return false; + return lldb::ChildCacheState::eRefetch; - return true; + return lldb::ChildCacheState::eReuse; } -size_t LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> +LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() { return 2; } lldb::ValueObjectSP -LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { +LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (m_pair_address != 0 && m_pair_type) { if (!m_pair_sp) m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, @@ -193,22 +194,22 @@ lldb_private::formatters::VectorIteratorSyntheticFrontEnd:: Update(); } -bool VectorIteratorSyntheticFrontEnd::Update() { +lldb::ChildCacheState VectorIteratorSyntheticFrontEnd::Update() { m_item_sp.reset(); ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP item_ptr = formatters::GetChildMemberWithName(*valobj_sp, m_item_names); if (!item_ptr) - return false; + return lldb::ChildCacheState::eRefetch; if (item_ptr->GetValueAsUnsigned(0) == 0) - return false; + return lldb::ChildCacheState::eRefetch; Status err; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); m_item_sp = CreateValueObjectFromAddress( @@ -216,13 +217,16 @@ bool VectorIteratorSyntheticFrontEnd::Update() { item_ptr->GetCompilerType().GetPointeeType()); if (err.Fail()) m_item_sp.reset(); - return false; + return lldb::ChildCacheState::eRefetch; } -size_t VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { return 1; } +llvm::Expected<uint32_t> +VectorIteratorSyntheticFrontEnd::CalculateNumChildren() { + return 1; +} lldb::ValueObjectSP -VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) { +VectorIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx == 0) return m_item_sp; return lldb::ValueObjectSP(); @@ -371,10 +375,13 @@ LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd( Update(); } -size_t LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { return 1; } +llvm::Expected<uint32_t> +LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() { + return 1; +} lldb::ValueObjectSP -LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { +LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx == 0) return m_ptr_obj->GetSP(); if (idx == 1) { @@ -390,23 +397,23 @@ LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { return lldb::ValueObjectSP(); } -bool LibStdcppSharedPtrSyntheticFrontEnd::Update() { +lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() { auto backend = m_backend.GetSP(); if (!backend) - return false; + return lldb::ChildCacheState::eRefetch; auto valobj_sp = backend->GetNonSyntheticValue(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr"); if (!ptr_obj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_obj = ptr_obj_sp->Clone(ConstString("pointer")).get(); m_obj_obj = nullptr; - return false; + return lldb::ChildCacheState::eRefetch; } bool LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren() { return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp index f1bfeae5099b..05199ba35b9a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp @@ -26,11 +26,11 @@ class LibStdcppTupleSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: explicit LibStdcppTupleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -53,19 +53,19 @@ LibStdcppTupleSyntheticFrontEnd::LibStdcppTupleSyntheticFrontEnd( Update(); } -bool LibStdcppTupleSyntheticFrontEnd::Update() { +lldb::ChildCacheState LibStdcppTupleSyntheticFrontEnd::Update() { m_members.clear(); ValueObjectSP valobj_backend_sp = m_backend.GetSP(); if (!valobj_backend_sp) - return false; + return lldb::ChildCacheState::eRefetch; ValueObjectSP next_child_sp = valobj_backend_sp->GetNonSyntheticValue(); while (next_child_sp != nullptr) { ValueObjectSP current_child = next_child_sp; next_child_sp = nullptr; - size_t child_count = current_child->GetNumChildren(); + size_t child_count = current_child->GetNumChildrenIgnoringErrors(); for (size_t i = 0; i < child_count; ++i) { ValueObjectSP child_sp = current_child->GetChildAtIndex(i); llvm::StringRef name_str = child_sp->GetName().GetStringRef(); @@ -83,19 +83,20 @@ bool LibStdcppTupleSyntheticFrontEnd::Update() { } } - return false; + return lldb::ChildCacheState::eRefetch; } bool LibStdcppTupleSyntheticFrontEnd::MightHaveChildren() { return true; } lldb::ValueObjectSP -LibStdcppTupleSyntheticFrontEnd::GetChildAtIndex(size_t idx) { +LibStdcppTupleSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx < m_members.size() && m_members[idx]) return m_members[idx]->GetSP(); return lldb::ValueObjectSP(); } -size_t LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> +LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() { return m_members.size(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index a84d641b57bc..92f540d9ca52 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -26,11 +26,11 @@ class LibStdcppUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: explicit LibStdcppUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -84,11 +84,11 @@ ValueObjectSP LibStdcppUniquePtrSyntheticFrontEnd::GetTuple() { return obj_child_sp; } -bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { +lldb::ChildCacheState LibStdcppUniquePtrSyntheticFrontEnd::Update() { ValueObjectSP tuple_sp = GetTuple(); if (!tuple_sp) - return false; + return lldb::ChildCacheState::eRefetch; std::unique_ptr<SyntheticChildrenFrontEnd> tuple_frontend( LibStdcppTupleSyntheticFrontEndCreator(nullptr, tuple_sp)); @@ -110,13 +110,13 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { } m_obj_obj = nullptr; - return false; + return lldb::ChildCacheState::eRefetch; } bool LibStdcppUniquePtrSyntheticFrontEnd::MightHaveChildren() { return true; } lldb::ValueObjectSP -LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { +LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { if (idx == 0 && m_ptr_obj) return m_ptr_obj->GetSP(); if (idx == 1 && m_del_obj) @@ -135,7 +135,8 @@ LibStdcppUniquePtrSyntheticFrontEnd::GetChildAtIndex(size_t idx) { return lldb::ValueObjectSP(); } -size_t LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> +LibStdcppUniquePtrSyntheticFrontEnd::CalculateNumChildren() { if (m_del_obj) return 2; return 1; diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index f1a7e04bc9d1..341923108e32 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -802,7 +802,7 @@ bool lldb_private::formatters::NSURLSummaryProvider( llvm::StringRef class_name = descriptor->GetClassName().GetStringRef(); - if (!class_name.equals("NSURL")) + if (class_name != "NSURL") return false; uint64_t offset_text = ptr_size + ptr_size + @@ -1038,13 +1038,15 @@ public: ~ObjCClassSyntheticChildrenFrontEnd() override = default; - size_t CalculateNumChildren() override { return 0; } + llvm::Expected<uint32_t> CalculateNumChildren() override { return 0; } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return lldb::ValueObjectSP(); } - bool Update() override { return false; } + lldb::ChildCacheState Update() override { + return lldb::ChildCacheState::eRefetch; + } bool MightHaveChildren() override { return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp index bd356a61161a..67d0cd08f51a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -50,11 +50,11 @@ public: ~NSArrayMSyntheticFrontEndBase() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override = 0; + lldb::ChildCacheState Update() override = 0; bool MightHaveChildren() override; @@ -81,7 +81,7 @@ public: ~GenericNSArrayMSyntheticFrontEnd() override; - bool Update() override; + lldb::ChildCacheState Update() override; protected: lldb::addr_t GetDataAddress() override; @@ -214,11 +214,11 @@ public: ~GenericNSArrayISyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -302,11 +302,11 @@ public: ~NSArray0SyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -319,11 +319,11 @@ public: ~NSArray1SyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -477,15 +477,15 @@ lldb_private::formatters:: : NSArrayMSyntheticFrontEndBase(valobj_sp), m_data_32(nullptr), m_data_64(nullptr) {} -size_t -lldb_private::formatters::NSArrayMSyntheticFrontEndBase::CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + NSArrayMSyntheticFrontEndBase::CalculateNumChildren() { return GetUsedCount(); } lldb::ValueObjectSP lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex( - size_t idx) { - if (idx >= CalculateNumChildren()) + uint32_t idx) { + if (idx >= CalculateNumChildrenIgnoringErrors()) return lldb::ValueObjectSP(); lldb::addr_t object_at_idx = GetDataAddress(); size_t pyhs_idx = idx; @@ -500,9 +500,8 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetChildAtIndex( } template <typename D32, typename D64> -bool -lldb_private::formatters:: - GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() { +lldb::ChildCacheState +lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; delete m_data_32; @@ -510,13 +509,13 @@ lldb_private::formatters:: delete m_data_64; m_data_64 = nullptr; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; if (m_ptr_size == 4) { @@ -529,7 +528,8 @@ lldb_private::formatters:: error); } - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool @@ -542,15 +542,14 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::GetIndexOfChildWithName ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } template <typename D32, typename D64> -lldb_private::formatters:: - GenericNSArrayMSyntheticFrontEnd<D32, D64>:: - ~GenericNSArrayMSyntheticFrontEnd<D32, D64>() { +lldb_private::formatters::GenericNSArrayMSyntheticFrontEnd<D32, D64>:: + GenericNSArrayMSyntheticFrontEnd::~GenericNSArrayMSyntheticFrontEnd() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -616,7 +615,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: template <typename D32, typename D64, bool Inline> lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: - ~GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>() { + GenericNSArrayISyntheticFrontEnd::~GenericNSArrayISyntheticFrontEnd() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -629,22 +628,22 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } template <typename D32, typename D64, bool Inline> -size_t -lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: - CalculateNumChildren() { +llvm::Expected<uint32_t> +lldb_private::formatters::GenericNSArrayISyntheticFrontEnd< + D32, D64, Inline>::CalculateNumChildren() { return m_data_32 ? m_data_32->used : m_data_64->used; } template <typename D32, typename D64, bool Inline> -bool -lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, + Inline>::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; delete m_data_32; @@ -652,13 +651,13 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: delete m_data_64; m_data_64 = nullptr; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; if (m_ptr_size == 4) { @@ -671,7 +670,8 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: error); } - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } template <typename D32, typename D64, bool Inline> @@ -684,8 +684,8 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: template <typename D32, typename D64, bool Inline> lldb::ValueObjectSP lldb_private::formatters::GenericNSArrayISyntheticFrontEnd<D32, D64, Inline>:: - GetChildAtIndex(size_t idx) { - if (idx >= CalculateNumChildren()) + GetChildAtIndex(uint32_t idx) { + if (idx >= CalculateNumChildrenIgnoringErrors()) return lldb::ValueObjectSP(); lldb::addr_t object_at_idx; if (Inline) { @@ -719,13 +719,14 @@ lldb_private::formatters::NSArray0SyntheticFrontEnd::GetIndexOfChildWithName( return UINT32_MAX; } -size_t +llvm::Expected<uint32_t> lldb_private::formatters::NSArray0SyntheticFrontEnd::CalculateNumChildren() { return 0; } -bool lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() { - return false; +lldb::ChildCacheState +lldb_private::formatters::NSArray0SyntheticFrontEnd::Update() { + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() { @@ -734,7 +735,7 @@ bool lldb_private::formatters::NSArray0SyntheticFrontEnd::MightHaveChildren() { lldb::ValueObjectSP lldb_private::formatters::NSArray0SyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { return lldb::ValueObjectSP(); } @@ -753,13 +754,14 @@ lldb_private::formatters::NSArray1SyntheticFrontEnd::GetIndexOfChildWithName( return UINT32_MAX; } -size_t +llvm::Expected<uint32_t> lldb_private::formatters::NSArray1SyntheticFrontEnd::CalculateNumChildren() { return 1; } -bool lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() { - return false; +lldb::ChildCacheState +lldb_private::formatters::NSArray1SyntheticFrontEnd::Update() { + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() { @@ -768,7 +770,7 @@ bool lldb_private::formatters::NSArray1SyntheticFrontEnd::MightHaveChildren() { lldb::ValueObjectSP lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { static const ConstString g_zero("[0]"); if (idx == 0) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 5ae0751cb065..ec6fd756394a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -103,11 +103,11 @@ public: ~NSDictionaryISyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -144,11 +144,11 @@ class NSConstantDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: NSConstantDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -176,11 +176,11 @@ class NSCFDictionarySyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: NSCFDictionarySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -209,11 +209,11 @@ public: ~NSDictionary1SyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -230,11 +230,11 @@ public: ~GenericNSDictionaryMSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -262,13 +262,13 @@ namespace Foundation1100 { NSDictionaryMSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); ~NSDictionaryMSyntheticFrontEnd() override; - - size_t CalculateNumChildren() override; - - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; - - bool Update() override; - + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + bool MightHaveChildren() override; size_t GetIndexOfChildWithName(ConstString name) override; @@ -601,19 +601,20 @@ size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + NSDictionaryISyntheticFrontEnd::CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; return (m_data_32 ? m_data_32->_used : m_data_64->_used); } -bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { m_children.clear(); delete m_data_32; m_data_32 = nullptr; @@ -622,13 +623,13 @@ bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { m_ptr_size = 0; ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; @@ -642,9 +643,9 @@ bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() { error); } if (error.Fail()) - return false; + return lldb::ChildCacheState::eRefetch; m_data_ptr = data_location + m_ptr_size; - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: @@ -654,8 +655,8 @@ bool lldb_private::formatters::NSDictionaryISyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex( - size_t idx) { - uint32_t num_children = CalculateNumChildren(); + uint32_t idx) { + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -738,32 +739,35 @@ size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); const uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + NSCFDictionarySyntheticFrontEnd::CalculateNumChildren() { if (!m_hashtable.IsValid()) return 0; return m_hashtable.GetCount(); } -bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); - return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); + return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref) + ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: @@ -773,11 +777,11 @@ bool lldb_private::formatters::NSCFDictionarySyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::NSCFDictionarySyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { lldb::addr_t m_keys_ptr = m_hashtable.GetKeyPointer(); lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); - const uint32_t num_children = CalculateNumChildren(); + const uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -871,40 +875,43 @@ size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + NSConstantDictionarySyntheticFrontEnd::CalculateNumChildren() { return m_size; } -bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd::Update() { ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); uint64_t valobj_addr = valobj_sp->GetValueAsUnsigned(0); m_size = process_sp->ReadUnsignedIntegerFromMemory( valobj_addr + 2 * m_ptr_size, m_ptr_size, 0, error); if (error.Fail()) - return false; + return lldb::ChildCacheState::eRefetch; m_keys_ptr = process_sp->ReadPointerFromMemory(valobj_addr + 3 * m_ptr_size, error); if (error.Fail()) - return false; + return lldb::ChildCacheState::eRefetch; m_objects_ptr = process_sp->ReadPointerFromMemory(valobj_addr + 4 * m_ptr_size, error); - return !error.Fail(); + + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: @@ -913,8 +920,8 @@ bool lldb_private::formatters::NSConstantDictionarySyntheticFrontEnd:: } lldb::ValueObjectSP lldb_private::formatters:: - NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(size_t idx) { - uint32_t num_children = CalculateNumChildren(); + NSConstantDictionarySyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -987,14 +994,15 @@ size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: return name == g_zero ? 0 : UINT32_MAX; } -size_t lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: - CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters:: + NSDictionary1SyntheticFrontEnd::CalculateNumChildren() { return 1; } -bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSDictionary1SyntheticFrontEnd::Update() { m_pair.reset(); - return false; + return lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: @@ -1004,7 +1012,7 @@ bool lldb_private::formatters::NSDictionary1SyntheticFrontEnd:: lldb::ValueObjectSP lldb_private::formatters::NSDictionary1SyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { if (idx != 0) return lldb::ValueObjectSP(); @@ -1059,8 +1067,9 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, D64>:: m_data_32(nullptr), m_data_64(nullptr), m_pair_type() {} template <typename D32, typename D64> -lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: - ~GenericNSDictionaryMSyntheticFrontEnd<D32,D64>() { +lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< + D32, D64>::GenericNSDictionaryMSyntheticFrontEnd:: + ~GenericNSDictionaryMSyntheticFrontEnd() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -1072,23 +1081,24 @@ size_t lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< D32, D64>::GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } template <typename D32, typename D64> -size_t -lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>::CalculateNumChildren() { +llvm::Expected<uint32_t> +lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< + D32, D64>::CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; - return (m_data_32 ? m_data_32->_used : m_data_64->_used); + return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used); } template <typename D32, typename D64> -bool -lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: - Update() { +lldb::ChildCacheState +lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32, + D64>::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; @@ -1097,13 +1107,13 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: delete m_data_64; m_data_64 = nullptr; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; @@ -1117,7 +1127,8 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: error); } - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } template <typename D32, typename D64> @@ -1130,7 +1141,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd<D32,D64>:: template <typename D32, typename D64> lldb::ValueObjectSP lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< - D32, D64>::GetChildAtIndex(size_t idx) { + D32, D64>::GetChildAtIndex(uint32_t idx) { lldb::addr_t m_keys_ptr; lldb::addr_t m_values_ptr; if (m_data_32) { @@ -1143,7 +1154,7 @@ lldb_private::formatters::GenericNSDictionaryMSyntheticFrontEnd< m_values_ptr = m_data_64->_buffer + (m_ptr_size * size); } - uint32_t num_children = CalculateNumChildren(); + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -1235,22 +1246,20 @@ lldb_private::formatters::Foundation1100:: NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t -lldb_private::formatters::Foundation1100:: - NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { +llvm::Expected<uint32_t> lldb_private::formatters::Foundation1100:: + NSDictionaryMSyntheticFrontEnd::CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; return (m_data_32 ? m_data_32->_used : m_data_64->_used); } -bool -lldb_private::formatters::Foundation1100:: - NSDictionaryMSyntheticFrontEnd::Update() { +lldb::ChildCacheState lldb_private::formatters::Foundation1100:: + NSDictionaryMSyntheticFrontEnd::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; @@ -1259,13 +1268,13 @@ lldb_private::formatters::Foundation1100:: delete m_data_64; m_data_64 = nullptr; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); Status error; error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; @@ -1279,7 +1288,8 @@ lldb_private::formatters::Foundation1100:: error); } - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool @@ -1290,13 +1300,13 @@ lldb_private::formatters::Foundation1100:: lldb::ValueObjectSP lldb_private::formatters::Foundation1100:: - NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(size_t idx) { + NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) { lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); - uint32_t num_children = CalculateNumChildren(); + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp index 99eeb2d5092f..5ef7edc7e80c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -116,7 +116,7 @@ public: // no need to delete m_child_ptr - it's kept alive by the cluster manager on // our behalf - size_t CalculateNumChildren() override { + llvm::Expected<uint32_t> CalculateNumChildren() override { if (m_child_ptr) return 1; if (m_child_sp) @@ -124,7 +124,7 @@ public: return 0; } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { if (idx != 0) return lldb::ValueObjectSP(); @@ -133,17 +133,17 @@ public: return m_child_sp; } - bool Update() override { + lldb::ChildCacheState Update() override { m_child_ptr = nullptr; m_child_sp.reset(); ProcessSP process_sp(m_backend.GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; lldb::addr_t userinfo_location = DerefToNSErrorPointer(m_backend); if (userinfo_location == LLDB_INVALID_ADDRESS) - return false; + return lldb::ChildCacheState::eRefetch; size_t ptr_size = process_sp->GetAddressByteSize(); @@ -152,17 +152,17 @@ public: lldb::addr_t userinfo = process_sp->ReadPointerFromMemory(userinfo_location, error); if (userinfo == LLDB_INVALID_ADDRESS || error.Fail()) - return false; + return lldb::ChildCacheState::eRefetch; InferiorSizedWord isw(userinfo, *process_sp); TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()); if (!scratch_ts_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_child_sp = CreateValueObjectFromData( "_userInfo", isw.GetAsData(process_sp->GetByteOrder()), m_backend.GetExecutionContextRef(), scratch_ts_sp->GetBasicType(lldb::eBasicTypeObjCID)); - return false; + return lldb::ChildCacheState::eRefetch; } bool MightHaveChildren() override { return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp index 29805bb2d5fe..e7ce26ea4c6f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -123,11 +123,9 @@ public: ~NSExceptionSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override { - return 4; - } + llvm::Expected<uint32_t> CalculateNumChildren() override { return 4; } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { switch (idx) { case 0: return m_name_sp; case 1: return m_reason_sp; @@ -137,14 +135,17 @@ public: return lldb::ValueObjectSP(); } - bool Update() override { + lldb::ChildCacheState Update() override { m_name_sp.reset(); m_reason_sp.reset(); m_userinfo_sp.reset(); m_reserved_sp.reset(); - return ExtractFields(m_backend, &m_name_sp, &m_reason_sp, &m_userinfo_sp, - &m_reserved_sp); + const auto ret = ExtractFields(m_backend, &m_name_sp, &m_reason_sp, + &m_userinfo_sp, &m_reserved_sp); + + return ret ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool MightHaveChildren() override { return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index 2a4ce80224e9..a434cee09d38 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -40,23 +40,25 @@ public: ~NSIndexPathSyntheticFrontEnd() override = default; - size_t CalculateNumChildren() override { return m_impl.GetNumIndexes(); } + llvm::Expected<uint32_t> CalculateNumChildren() override { + return m_impl.GetNumIndexes(); + } - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override { + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { return m_impl.GetIndexAtIndex(idx, m_uint_star_type); } - bool Update() override { + lldb::ChildCacheState Update() override { m_impl.Clear(); auto type_system = m_backend.GetCompilerType().GetTypeSystem(); if (!type_system) - return false; + return lldb::ChildCacheState::eRefetch; auto ast = ScratchTypeSystemClang::GetForTarget( *m_backend.GetExecutionContextRef().GetTargetSP()); if (!ast) - return false; + return lldb::ChildCacheState::eRefetch; m_uint_star_type = ast->GetPointerSizedIntType(false); @@ -65,18 +67,18 @@ public: ProcessSP process_sp = m_backend.GetProcessSP(); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); if (!runtime) - return false; + return lldb::ChildCacheState::eRefetch; ObjCLanguageRuntime::ClassDescriptorSP descriptor( runtime->GetClassDescriptor(m_backend)); if (!descriptor.get() || !descriptor->IsValid()) - return false; + return lldb::ChildCacheState::eRefetch; uint64_t info_bits(0), value_bits(0), payload(0); @@ -119,7 +121,7 @@ public: } } } - return false; + return lldb::ChildCacheState::eRefetch; } bool MightHaveChildren() override { return m_impl.m_mode != Mode::Invalid; } @@ -127,7 +129,7 @@ public: size_t GetIndexOfChildWithName(ConstString name) override { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 44097ee0c42b..7d0a6a507211 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -46,11 +46,11 @@ public: ~NSSetISyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -84,11 +84,11 @@ class NSCFSetSyntheticFrontEnd : public SyntheticChildrenFrontEnd { public: NSCFSetSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -117,11 +117,11 @@ public: ~GenericNSSetMSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -233,11 +233,11 @@ public: ~NSSetCodeRunningSyntheticFrontEnd() override; - size_t CalculateNumChildren() override; + llvm::Expected<uint32_t> CalculateNumChildren() override; - lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; - bool Update() override; + lldb::ChildCacheState Update() override; bool MightHaveChildren() override; @@ -414,19 +414,20 @@ lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName( ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t +llvm::Expected<uint32_t> lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; return (m_data_32 ? m_data_32->_used : m_data_64->_used); } -bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { m_children.clear(); delete m_data_32; m_data_32 = nullptr; @@ -435,13 +436,13 @@ bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { m_ptr_size = 0; ValueObjectSP valobj_sp = m_backend.GetSP(); if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; Status error; @@ -455,9 +456,9 @@ bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { error); } if (error.Fail()) - return false; + return lldb::ChildCacheState::eRefetch; m_data_ptr = data_location + m_ptr_size; - return true; + return lldb::ChildCacheState::eReuse; } bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() { @@ -465,8 +466,9 @@ bool lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren() { } lldb::ValueObjectSP -lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex(size_t idx) { - uint32_t num_children = CalculateNumChildren(); +lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -549,32 +551,35 @@ lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetIndexOfChildWithName( ConstString name) { const char *item_name = name.GetCString(); const uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } -size_t +llvm::Expected<uint32_t> lldb_private::formatters::NSCFSetSyntheticFrontEnd::CalculateNumChildren() { if (!m_hashtable.IsValid()) return 0; return m_hashtable.GetCount(); } -bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() { +lldb::ChildCacheState +lldb_private::formatters::NSCFSetSyntheticFrontEnd::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); m_order = process_sp->GetByteOrder(); - return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref); + return m_hashtable.Update(valobj_sp->GetValueAsUnsigned(0), m_exe_ctx_ref) + ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() { @@ -583,10 +588,10 @@ bool lldb_private::formatters::NSCFSetSyntheticFrontEnd::MightHaveChildren() { lldb::ValueObjectSP lldb_private::formatters::NSCFSetSyntheticFrontEnd::GetChildAtIndex( - size_t idx) { + uint32_t idx) { lldb::addr_t m_values_ptr = m_hashtable.GetValuePointer(); - const uint32_t num_children = CalculateNumChildren(); + const uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); @@ -671,8 +676,8 @@ lldb_private::formatters::GenericNSSetMSyntheticFrontEnd< } template <typename D32, typename D64> -lldb_private::formatters:: - GenericNSSetMSyntheticFrontEnd<D32, D64>::~GenericNSSetMSyntheticFrontEnd<D32, D64>() { +lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>:: + GenericNSSetMSyntheticFrontEnd::~GenericNSSetMSyntheticFrontEnd() { delete m_data_32; m_data_32 = nullptr; delete m_data_64; @@ -686,24 +691,23 @@ lldb_private::formatters:: ConstString name) { const char *item_name = name.GetCString(); uint32_t idx = ExtractIndexFromString(item_name); - if (idx < UINT32_MAX && idx >= CalculateNumChildren()) + if (idx < UINT32_MAX && idx >= CalculateNumChildrenIgnoringErrors()) return UINT32_MAX; return idx; } template <typename D32, typename D64> -size_t -lldb_private::formatters:: - GenericNSSetMSyntheticFrontEnd<D32, D64>::CalculateNumChildren() { +llvm::Expected<uint32_t> +lldb_private::formatters::GenericNSSetMSyntheticFrontEnd< + D32, D64>::CalculateNumChildren() { if (!m_data_32 && !m_data_64) return 0; - return (m_data_32 ? m_data_32->_used : m_data_64->_used); + return (m_data_32 ? (uint32_t)m_data_32->_used : (uint32_t)m_data_64->_used); } template <typename D32, typename D64> -bool -lldb_private::formatters:: - GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() { +lldb::ChildCacheState +lldb_private::formatters::GenericNSSetMSyntheticFrontEnd<D32, D64>::Update() { m_children.clear(); ValueObjectSP valobj_sp = m_backend.GetSP(); m_ptr_size = 0; @@ -712,13 +716,13 @@ lldb_private::formatters:: delete m_data_64; m_data_64 = nullptr; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; if (!valobj_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) - return false; + return lldb::ChildCacheState::eRefetch; m_ptr_size = process_sp->GetAddressByteSize(); uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; Status error; @@ -731,7 +735,8 @@ lldb_private::formatters:: process_sp->ReadMemory(data_location, m_data_64, sizeof(D64), error); } - return error.Success(); + return error.Success() ? lldb::ChildCacheState::eReuse + : lldb::ChildCacheState::eRefetch; } template <typename D32, typename D64> @@ -744,11 +749,11 @@ lldb_private::formatters:: template <typename D32, typename D64> lldb::ValueObjectSP lldb_private::formatters:: - GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(size_t idx) { + GenericNSSetMSyntheticFrontEnd<D32, D64>::GetChildAtIndex(uint32_t idx) { lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); - uint32_t num_children = CalculateNumChildren(); + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); if (idx >= num_children) return lldb::ValueObjectSP(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h index a50f4b036108..d9c0cd3c18cf 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/contrib/llvm-project/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -194,6 +194,8 @@ public: llvm::StringRef GetInstanceVariableName() override { return "self"; } + bool SupportsExceptionBreakpointsOnThrow() const override { return true; } + // PluginInterface protocol llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } }; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 300ecc8e8ed5..c7202a47d015 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -47,16 +47,17 @@ bool CPPLanguageRuntime::IsAllowedRuntimeValue(ConstString name) { return name == g_this || name == g_promise || name == g_coro_frame; } -bool CPPLanguageRuntime::GetObjectDescription(Stream &str, - ValueObject &object) { +llvm::Error CPPLanguageRuntime::GetObjectDescription(Stream &str, + ValueObject &object) { // C++ has no generic way to do this. - return false; + return llvm::createStringError("C++ does not support object descriptions"); } -bool CPPLanguageRuntime::GetObjectDescription( - Stream &str, Value &value, ExecutionContextScope *exe_scope) { +llvm::Error +CPPLanguageRuntime::GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) { // C++ has no generic way to do this. - return false; + return llvm::createStringError("C++ does not support object descriptions"); } bool contains_lambda_identifier(llvm::StringRef &str_ref) { diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 1be58b7bf9ea..57cfe2824580 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -59,10 +59,10 @@ public: process.GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus)); } - bool GetObjectDescription(Stream &str, ValueObject &object) override; + llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override; - bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) override; + llvm::Error GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override; /// Obtain a ThreadPlan to get us into C++ constructs such as std::function. /// diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 47b1db16f1e9..7af768aad0bc 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -419,19 +419,7 @@ public: : CommandObjectParsed( interpreter, "demangle", "Demangle a C++ mangled name.", "language cplusplus demangle [<mangled-name> ...]") { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeSymbol; - index_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeSymbol, eArgRepeatPlus); } ~CommandObjectMultiwordItaniumABI_Demangle() override = default; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 5d7c5f38d180..6894cdccaf95 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -316,7 +316,7 @@ public: const bool HasRelatedResultType = false; const bool for_expression = true; - std::vector<clang::IdentifierInfo *> selector_components; + std::vector<const clang::IdentifierInfo *> selector_components; const char *name_cursor = name; bool is_zero_argument = true; @@ -335,7 +335,7 @@ public: } } - clang::IdentifierInfo **identifier_infos = selector_components.data(); + const clang::IdentifierInfo **identifier_infos = selector_components.data(); if (!identifier_infos) { return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index f08f9f0f815d..5ff267720629 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -31,6 +31,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/ErrorMessages.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Scalar.h" @@ -67,20 +68,21 @@ void AppleObjCRuntime::Terminate() { AppleObjCRuntimeV1::Terminate(); } -bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) { +llvm::Error AppleObjCRuntime::GetObjectDescription(Stream &str, + ValueObject &valobj) { CompilerType compiler_type(valobj.GetCompilerType()); bool is_signed; // ObjC objects can only be pointers (or numbers that actually represents // pointers but haven't been typecast, because reasons..) if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType()) - return false; + return llvm::createStringError("not a pointer type"); // Make the argument list: we pass one arg, the address of our pointer, to // the print function. Value val; if (!valobj.ResolveValue(val.GetScalar())) - return false; + return llvm::createStringError("pointer value could not be resolved"); // Value Objects may not have a process in their ExecutionContextRef. But we // need to have one in the ref we pass down to eventually call description. @@ -91,20 +93,22 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) { } else { exe_ctx.SetContext(valobj.GetTargetSP(), true); if (!exe_ctx.HasProcessScope()) - return false; + return llvm::createStringError("no process"); } return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); } -bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, - ExecutionContextScope *exe_scope) { + +llvm::Error +AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, + ExecutionContextScope *exe_scope) { if (!m_read_objc_library) - return false; + return llvm::createStringError("Objective-C runtime not loaded"); ExecutionContext exe_ctx; exe_scope->CalculateExecutionContext(exe_ctx); Process *process = exe_ctx.GetProcessPtr(); if (!process) - return false; + return llvm::createStringError("no process"); // We need other parts of the exe_ctx, but the processes have to match. assert(m_process == process); @@ -112,25 +116,25 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, // Get the function address for the print function. const Address *function_address = GetPrintForDebuggerAddr(); if (!function_address) - return false; + return llvm::createStringError("no print function"); Target *target = exe_ctx.GetTargetPtr(); CompilerType compiler_type = value.GetCompilerType(); if (compiler_type) { - if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type)) { - strm.Printf("Value doesn't point to an ObjC object.\n"); - return false; - } + if (!TypeSystemClang::IsObjCObjectPointerType(compiler_type)) + return llvm::createStringError( + "Value doesn't point to an ObjC object.\n"); } else { // If it is not a pointer, see if we can make it into a pointer. TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(*target); if (!scratch_ts_sp) - return false; + return llvm::createStringError("no scratch type system"); CompilerType opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeObjCID); if (!opaque_type) - opaque_type = scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType(); + opaque_type = + scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType(); // value.SetContext(Value::eContextTypeClangType, opaque_type_ptr); value.SetCompilerType(opaque_type); } @@ -142,14 +146,14 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, TypeSystemClangSP scratch_ts_sp = ScratchTypeSystemClang::GetForTarget(*target); if (!scratch_ts_sp) - return false; + return llvm::createStringError("no scratch type system"); CompilerType return_compiler_type = scratch_ts_sp->GetCStringType(true); Value ret; // ret.SetContext(Value::eContextTypeClangType, return_compiler_type); ret.SetCompilerType(return_compiler_type); - if (exe_ctx.GetFramePtr() == nullptr) { + if (!exe_ctx.GetFramePtr()) { Thread *thread = exe_ctx.GetThreadPtr(); if (thread == nullptr) { exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread()); @@ -173,10 +177,11 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, arg_value_list, "objc-object-description", error)); if (error.Fail()) { m_print_object_caller_up.reset(); - strm.Printf("Could not get function runner to call print for debugger " - "function: %s.", - error.AsCString()); - return false; + return llvm::createStringError( + llvm::Twine( + "could not get function runner to call print for debugger " + "function: ") + + error.AsCString()); } m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr, diagnostics); @@ -195,10 +200,9 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, ExpressionResults results = m_print_object_caller_up->ExecuteFunction( exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); - if (results != eExpressionCompleted) { - strm.Printf("Error evaluating Print Object function: %d.\n", results); - return false; - } + if (results != eExpressionCompleted) + return llvm::createStringError( + "could not evaluate print object function: " + toString(results)); addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); @@ -213,7 +217,9 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, strm.Write(buf, curr_len); cstr_len += curr_len; } - return cstr_len > 0; + if (cstr_len > 0) + return llvm::Error::success(); + return llvm::createStringError("empty object description"); } lldb::ModuleSP AppleObjCRuntime::GetObjCModule() { @@ -539,7 +545,8 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( return object; }; - for (size_t idx = 0; idx < reserved_dict->GetNumChildren(); idx++) { + for (size_t idx = 0; idx < reserved_dict->GetNumChildrenIgnoringErrors(); + idx++) { ValueObjectSP dict_entry = reserved_dict->GetChildAtIndex(idx); DataExtractor data; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index cfeec3d679be..da58d44db19a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -44,10 +44,10 @@ public: } // These are generic runtime functions: - bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) override; + llvm::Error GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override; - bool GetObjectDescription(Stream &str, ValueObject &object) override; + llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override; bool CouldHaveDynamicValue(ValueObject &in_value) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index f380d6e7e672..9409497f1c81 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -897,19 +897,7 @@ public: eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), m_options() { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeRegularExpression; - index_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeRegularExpression, eArgRepeatOptional); } ~CommandObjectObjC_ClassTable_Dump() override = default; @@ -1015,19 +1003,7 @@ public: "language objc tagged-pointer info", eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeAddress; - index_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the - // argument entry. - arg.push_back(index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back(arg); + AddSimpleArgumentList(eArgTypeAddress, eArgRepeatPlus); } ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default; @@ -1893,15 +1869,15 @@ AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper( if (loader->IsFullyInitialized()) { switch (exe_ctx.GetTargetRef().GetDynamicClassInfoHelper()) { case eDynamicClassInfoHelperAuto: - LLVM_FALLTHROUGH; + [[fallthrough]]; case eDynamicClassInfoHelperGetRealizedClassList: if (m_runtime.m_has_objc_getRealizedClassList_trylock) return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock; - LLVM_FALLTHROUGH; + [[fallthrough]]; case eDynamicClassInfoHelperCopyRealizedClassList: if (m_runtime.m_has_objc_copyRealizedClassList) return DynamicClassInfoExtractor::objc_copyRealizedClassList; - LLVM_FALLTHROUGH; + [[fallthrough]]; case eDynamicClassInfoHelperRealizedClassesStruct: return DynamicClassInfoExtractor::gdb_objc_realized_classes; } @@ -3178,7 +3154,7 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); int64_t data_payload_signed = - ((int64_t)((int64_t)unobfuscated + ((int64_t)((uint64_t)unobfuscated << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index ca582cb1d5a4..ddaa7a8a597b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -13,6 +13,8 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/StringLexer.h" #include "clang/Basic/TargetInfo.h" @@ -234,12 +236,15 @@ clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( auto types = decl_vendor->FindTypes(ConstString(name), /*max_matches*/ 1); - // The user can forward-declare something that has no definition. The runtime - // doesn't prohibit this at all. This is a rare and very weird case. We keep - // this assert in debug builds so we catch other weird cases. - lldbassert(!types.empty()); - if (types.empty()) + if (types.empty()) { + // The user can forward-declare something that has no definition. The + // runtime doesn't prohibit this at all. This is a rare and very weird + // case. Assert assert in debug builds so we catch other weird cases. + assert(false && "forward declaration without definition"); + LLDB_LOG(GetLog(LLDBLog::Types), + "forward declaration without definition: {0}", name); return ast_ctx.getObjCIdType(); + } return ClangUtil::GetQualType(types.front().GetPointerType()); } else { diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp index 39b3e816f4be..58b838752be5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.cpp @@ -104,15 +104,17 @@ GNUstepObjCRuntime::GNUstepObjCRuntime(Process *process) ReadObjCLibraryIfNeeded(process->GetTarget().GetImages()); } -bool GNUstepObjCRuntime::GetObjectDescription(Stream &str, - ValueObject &valobj) { - // TODO: ObjC has a generic way to do this - return false; +llvm::Error GNUstepObjCRuntime::GetObjectDescription(Stream &str, + ValueObject &valobj) { + return llvm::createStringError( + "LLDB's GNUStep runtime does not support object description"); } -bool GNUstepObjCRuntime::GetObjectDescription( - Stream &strm, Value &value, ExecutionContextScope *exe_scope) { - // TODO: ObjC has a generic way to do this - return false; + +llvm::Error +GNUstepObjCRuntime::GetObjectDescription(Stream &strm, Value &value, + ExecutionContextScope *exe_scope) { + return llvm::createStringError( + "LLDB's GNUStep runtime does not support object description"); } bool GNUstepObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) { diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h index b22088807f97..de24466ebb00 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/GNUstepObjCRuntime.h @@ -57,10 +57,10 @@ public: // // LanguageRuntime implementation // - bool GetObjectDescription(Stream &str, Value &value, - ExecutionContextScope *exe_scope) override; + llvm::Error GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override; - bool GetObjectDescription(Stream &str, ValueObject &object) override; + llvm::Error GetObjectDescription(Stream &str, ValueObject &object) override; bool CouldHaveDynamicValue(ValueObject &in_value) override; diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index ba52444f0c2f..a812ffba7a64 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -350,18 +350,17 @@ ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { return nullptr; } -bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, - uint64_t &size) { +std::optional<uint64_t> +ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type) { void *opaque_ptr = compiler_type.GetOpaqueQualType(); - size = m_type_size_cache.Lookup(opaque_ptr); - // an ObjC object will at least have an ISA, so 0 is definitely not OK - if (size > 0) - return true; + uint64_t cached_size = m_type_size_cache.Lookup(opaque_ptr); + if (cached_size > 0) + return cached_size; ClassDescriptorSP class_descriptor_sp = GetClassDescriptorFromClassName(compiler_type.GetTypeName()); if (!class_descriptor_sp) - return false; + return {}; int32_t max_offset = INT32_MIN; uint64_t sizeof_max = 0; @@ -377,11 +376,13 @@ bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, } } - size = 8 * (max_offset + sizeof_max); - if (found) + uint64_t size = 8 * (max_offset + sizeof_max); + if (found && size > 0) { m_type_size_cache.Insert(opaque_ptr, size); + return size; + } - return found; + return {}; } lldb::BreakpointPreconditionSP diff --git a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index 0a8b6e8d56ed..ffe9725fa682 100644 --- a/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -107,7 +107,7 @@ public: int64_t *value_bits = nullptr, uint64_t *payload = nullptr) = 0; /// @} - + virtual uint64_t GetInstanceSize() = 0; // use to implement version-specific additional constraints on pointers @@ -321,8 +321,8 @@ public: m_negative_complete_class_cache.clear(); } - bool GetTypeBitSize(const CompilerType &compiler_type, - uint64_t &size) override; + std::optional<uint64_t> + GetTypeBitSize(const CompilerType &compiler_type) override; /// Check whether the name is "self" or "_cmd" and should show up in /// "frame variable". diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp index 2dc71d85777c..76141f797641 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/ObjectContainerMachOFileset.cpp @@ -159,9 +159,9 @@ ParseFileset(DataExtractor &data, mach_header header, fileset_entry_command entry; data.CopyData(load_cmd_offset, sizeof(fileset_entry_command), &entry); lldb::offset_t entry_id_offset = load_cmd_offset + entry.entry_id.offset; - const char *id = data.GetCStr(&entry_id_offset); - entries.emplace_back(entry.vmaddr + slide, entry.fileoff, - std::string(id)); + if (const char *id = data.GetCStr(&entry_id_offset)) + entries.emplace_back(entry.vmaddr + slide, entry.fileoff, + std::string(id)); } offset = load_cmd_offset + lc.cmdsize; diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 0d95a1c12bde..890db5c27481 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -717,6 +717,20 @@ bool ObjectFileELF::SetLoadAddress(Target &target, lldb::addr_t value, // Iterate through the object file sections to find all of the sections // that have SHF_ALLOC in their flag bits. SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + + // PT_TLS segments can have the same p_vaddr and p_paddr as other + // PT_LOAD segments so we shouldn't load them. If we do load them, then + // the SectionLoadList will incorrectly fill in the instance variable + // SectionLoadList::m_addr_to_sect with the same address as a PT_LOAD + // segment and we won't be able to resolve addresses in the PT_LOAD + // segment whose p_vaddr entry matches that of the PT_TLS. Any variables + // that appear in the PT_TLS segments get resolved by the DWARF + // expressions. If this ever changes we will need to fix all object + // file plug-ins, but until then, we don't want PT_TLS segments to + // remove the entry from SectionLoadList::m_addr_to_sect when we call + // SetSectionLoadAddress() below. + if (section_sp->IsThreadSpecific()) + continue; if (section_sp->Test(SHF_ALLOC) || section_sp->GetType() == eSectionTypeContainer) { lldb::addr_t load_addr = section_sp->GetFileAddress(); @@ -1682,7 +1696,6 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { return llvm::StringSwitch<SectionType>(Name) .Case(".ARM.exidx", eSectionTypeARMexidx) .Case(".ARM.extab", eSectionTypeARMextab) - .Cases(".bss", ".tbss", eSectionTypeZeroFill) .Case(".ctf", eSectionTypeDebug) .Cases(".data", ".tdata", eSectionTypeData) .Case(".eh_frame", eSectionTypeEHFrame) @@ -1699,6 +1712,10 @@ SectionType ObjectFileELF::GetSectionType(const ELFSectionHeaderInfo &H) const { if (H.sh_flags & SHF_EXECINSTR) return eSectionTypeCode; break; + case SHT_NOBITS: + if (H.sh_flags & SHF_ALLOC) + return eSectionTypeZeroFill; + break; case SHT_SYMTAB: return eSectionTypeELFSymbolTable; case SHT_DYNSYM: @@ -1854,6 +1871,39 @@ public: }; } +// We have to do this because ELF doesn't have section IDs, and also +// doesn't require section names to be unique. (We use the section index +// for section IDs, but that isn't guaranteed to be the same in separate +// debug images.) +static SectionSP FindMatchingSection(const SectionList §ion_list, + SectionSP section) { + SectionSP sect_sp; + + addr_t vm_addr = section->GetFileAddress(); + ConstString name = section->GetName(); + offset_t byte_size = section->GetByteSize(); + bool thread_specific = section->IsThreadSpecific(); + uint32_t permissions = section->GetPermissions(); + uint32_t alignment = section->GetLog2Align(); + + for (auto sect : section_list) { + if (sect->GetName() == name && + sect->IsThreadSpecific() == thread_specific && + sect->GetPermissions() == permissions && + sect->GetByteSize() == byte_size && sect->GetFileAddress() == vm_addr && + sect->GetLog2Align() == alignment) { + sect_sp = sect; + break; + } else { + sect_sp = FindMatchingSection(sect->GetChildren(), section); + if (sect_sp) + break; + } + } + + return sect_sp; +} + void ObjectFileELF::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; @@ -2027,13 +2077,17 @@ static char FindArmAarch64MappingSymbol(const char *symbol_name) { #define IS_MICROMIPS(ST_OTHER) (((ST_OTHER)&STO_MIPS_ISA) == STO_MICROMIPS) // private -unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, - SectionList *section_list, - const size_t num_symbols, - const DataExtractor &symtab_data, - const DataExtractor &strtab_data) { +std::pair<unsigned, ObjectFileELF::FileAddressToAddressClassMap> +ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, + SectionList *section_list, const size_t num_symbols, + const DataExtractor &symtab_data, + const DataExtractor &strtab_data) { ELFSymbol symbol; lldb::offset_t offset = 0; + // The changes these symbols would make to the class map. We will also update + // m_address_class_map but need to tell the caller what changed because the + // caller may be another object file. + FileAddressToAddressClassMap address_class_map; static ConstString text_section_name(".text"); static ConstString init_section_name(".init"); @@ -2067,10 +2121,12 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, SectionList *module_section_list = module_sp ? module_sp->GetSectionList() : nullptr; - // Local cache to avoid doing a FindSectionByName for each symbol. The "const - // char*" key must came from a ConstString object so they can be compared by - // pointer - std::unordered_map<const char *, lldb::SectionSP> section_name_to_section; + // We might have debug information in a separate object, in which case + // we need to map the sections from that object to the sections in the + // main object during symbol lookup. If we had to compare the sections + // for every single symbol, that would be expensive, so this map is + // used to accelerate the process. + std::unordered_map<lldb::SectionSP, lldb::SectionSP> section_map; unsigned i; for (i = 0; i < num_symbols; ++i) { @@ -2178,18 +2234,18 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'a': // $a[.<any>]* - marks an ARM instruction sequence - m_address_class_map[symbol.st_value] = AddressClass::eCode; + address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'b': case 't': // $b[.<any>]* - marks a THUMB BL instruction sequence // $t[.<any>]* - marks a THUMB instruction sequence - m_address_class_map[symbol.st_value] = + address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = AddressClass::eData; + address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2203,11 +2259,11 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, switch (mapping_symbol) { case 'x': // $x[.<any>]* - marks an A64 instruction sequence - m_address_class_map[symbol.st_value] = AddressClass::eCode; + address_class_map[symbol.st_value] = AddressClass::eCode; break; case 'd': // $d[.<any>]* - marks a data item sequence (e.g. lit pool) - m_address_class_map[symbol.st_value] = AddressClass::eData; + address_class_map[symbol.st_value] = AddressClass::eData; break; } } @@ -2225,11 +2281,11 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, // conjunction with symbol.st_value to produce the final // symbol_value that we store in the symtab. symbol_value_offset = -1; - m_address_class_map[symbol.st_value ^ 1] = + address_class_map[symbol.st_value ^ 1] = AddressClass::eCodeAlternateISA; } else { // This address is ARM - m_address_class_map[symbol.st_value] = AddressClass::eCode; + address_class_map[symbol.st_value] = AddressClass::eCode; } } } @@ -2250,17 +2306,17 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, */ if (arch.IsMIPS()) { if (IS_MICROMIPS(symbol.st_other)) - m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; + address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; else if ((symbol.st_value & 1) && (symbol_type == eSymbolTypeCode)) { symbol.st_value = symbol.st_value & (~1ull); - m_address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; + address_class_map[symbol.st_value] = AddressClass::eCodeAlternateISA; } else { if (symbol_type == eSymbolTypeCode) - m_address_class_map[symbol.st_value] = AddressClass::eCode; + address_class_map[symbol.st_value] = AddressClass::eCode; else if (symbol_type == eSymbolTypeData) - m_address_class_map[symbol.st_value] = AddressClass::eData; + address_class_map[symbol.st_value] = AddressClass::eData; else - m_address_class_map[symbol.st_value] = AddressClass::eUnknown; + address_class_map[symbol.st_value] = AddressClass::eUnknown; } } } @@ -2275,14 +2331,14 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, if (symbol_section_sp && module_section_list && module_section_list != section_list) { - ConstString sect_name = symbol_section_sp->GetName(); - auto section_it = section_name_to_section.find(sect_name.GetCString()); - if (section_it == section_name_to_section.end()) - section_it = - section_name_to_section - .emplace(sect_name.GetCString(), - module_section_list->FindSectionByName(sect_name)) - .first; + auto section_it = section_map.find(symbol_section_sp); + if (section_it == section_map.end()) { + section_it = section_map + .emplace(symbol_section_sp, + FindMatchingSection(*module_section_list, + symbol_section_sp)) + .first; + } if (section_it->second) symbol_section_sp = section_it->second; } @@ -2321,13 +2377,30 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, bool symbol_size_valid = symbol.st_size != 0 || symbol.getType() != STT_FUNC; + bool is_trampoline = false; + if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64)) { + // On AArch64, trampolines are registered as code. + // If we detect a trampoline (which starts with __AArch64ADRPThunk_ or + // __AArch64AbsLongThunk_) we register the symbol as a trampoline. This + // way we will be able to detect the trampoline when we step in a function + // and step through the trampoline. + if (symbol_type == eSymbolTypeCode) { + llvm::StringRef trampoline_name = mangled.GetName().GetStringRef(); + if (trampoline_name.starts_with("__AArch64ADRPThunk_") || + trampoline_name.starts_with("__AArch64AbsLongThunk_")) { + symbol_type = eSymbolTypeTrampoline; + is_trampoline = true; + } + } + } + Symbol dc_symbol( i + start_id, // ID is the original symbol table index. mangled, symbol_type, // Type of this symbol is_global, // Is this globally visible? false, // Is this symbol debug info? - false, // Is this symbol a trampoline? + is_trampoline, // Is this symbol a trampoline? false, // Is this symbol artificial? AddressRange(symbol_section_sp, // Section in which this symbol is // defined or null. @@ -2340,24 +2413,33 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, dc_symbol.SetIsWeak(true); symtab->AddSymbol(dc_symbol); } - return i; + + m_address_class_map.merge(address_class_map); + return {i, address_class_map}; } -unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, - user_id_t start_id, - lldb_private::Section *symtab) { +std::pair<unsigned, ObjectFileELF::FileAddressToAddressClassMap> +ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, + lldb_private::Section *symtab) { if (symtab->GetObjectFile() != this) { // If the symbol table section is owned by a different object file, have it // do the parsing. ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile()); - return obj_file_elf->ParseSymbolTable(symbol_table, start_id, symtab); + auto [num_symbols, address_class_map] = + obj_file_elf->ParseSymbolTable(symbol_table, start_id, symtab); + + // The other object file returned the changes it made to its address + // class map, make the same changes to ours. + m_address_class_map.merge(address_class_map); + + return {num_symbols, address_class_map}; } // Get section list for this object file. SectionList *section_list = m_sections_up.get(); if (!section_list) - return 0; + return {}; user_id_t symtab_id = symtab->GetID(); const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id); @@ -2383,7 +2465,7 @@ unsigned ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, } } - return 0; + return {0, {}}; } size_t ObjectFileELF::ParseDynamicSymbols() { @@ -2920,8 +3002,12 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) { // while the reverse is not necessarily true. Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); - if (symtab) - symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, symtab); + if (symtab) { + auto [num_symbols, address_class_map] = + ParseSymbolTable(&lldb_symtab, symbol_id, symtab); + m_address_class_map.merge(address_class_map); + symbol_id += num_symbols; + } // The symtab section is non-allocable and can be stripped, while the // .dynsym section which should always be always be there. To support the @@ -2934,8 +3020,12 @@ void ObjectFileELF::ParseSymtab(Symtab &lldb_symtab) { Section *dynsym = section_list->FindSectionByType(eSectionTypeELFDynamicSymbols, true) .get(); - if (dynsym) - symbol_id += ParseSymbolTable(&lldb_symtab, symbol_id, dynsym); + if (dynsym) { + auto [num_symbols, address_class_map] = + ParseSymbolTable(&lldb_symtab, symbol_id, dynsym); + symbol_id += num_symbols; + m_address_class_map.merge(address_class_map); + } } // DT_JMPREL @@ -3484,7 +3574,7 @@ ObjectFile::Strata ObjectFileELF::CalculateStrata() { // decrease by one llvm::StringRef loader_name(buffer, read_size - 1); llvm::StringRef freebsd_kernel_loader_name("/red/herring"); - if (loader_name.equals(freebsd_kernel_loader_name)) + if (loader_name == freebsd_kernel_loader_name) return eStrataKernel; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index bc8e34981a9d..844e981b1d89 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -187,6 +187,9 @@ private: typedef DynamicSymbolColl::iterator DynamicSymbolCollIter; typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter; + /// An ordered map of file address to address class. Used on architectures + /// like Arm where there is an alternative ISA mode like Thumb. The container + /// is ordered so that it can be binary searched. typedef std::map<lldb::addr_t, lldb_private::AddressClass> FileAddressToAddressClassMap; @@ -285,18 +288,19 @@ private: /// Populates the symbol table with all non-dynamic linker symbols. This /// method will parse the symbols only once. Returns the number of symbols - /// parsed. - unsigned ParseSymbolTable(lldb_private::Symtab *symbol_table, - lldb::user_id_t start_id, - lldb_private::Section *symtab); + /// parsed and a map of address types (used by targets like Arm that have + /// an alternative ISA mode like Thumb). + std::pair<unsigned, FileAddressToAddressClassMap> + ParseSymbolTable(lldb_private::Symtab *symbol_table, lldb::user_id_t start_id, + lldb_private::Section *symtab); /// Helper routine for ParseSymbolTable(). - unsigned ParseSymbols(lldb_private::Symtab *symbol_table, - lldb::user_id_t start_id, - lldb_private::SectionList *section_list, - const size_t num_symbols, - const lldb_private::DataExtractor &symtab_data, - const lldb_private::DataExtractor &strtab_data); + std::pair<unsigned, FileAddressToAddressClassMap> + ParseSymbols(lldb_private::Symtab *symbol_table, lldb::user_id_t start_id, + lldb_private::SectionList *section_list, + const size_t num_symbols, + const lldb_private::DataExtractor &symtab_data, + const lldb_private::DataExtractor &strtab_data); /// Scans the relocation entries and adds a set of artificial symbols to the /// given symbol table for each PLT slot. Returns the number of symbols diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index 50d1b563f469..de212c6b20da 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -14,28 +14,106 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/Section.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/ThreadList.h" +#include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RangeMap.h" #include "lldb/Utility/RegisterValue.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Minidump.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/TargetParser/Triple.h" #include "Plugins/Process/minidump/MinidumpTypes.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" +#include <algorithm> #include <cinttypes> +#include <climits> +#include <cstddef> +#include <cstdint> +#include <functional> +#include <iostream> +#include <set> +#include <utility> +#include <vector> using namespace lldb; using namespace lldb_private; using namespace llvm::minidump; -void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) { +Status MinidumpFileBuilder::AddHeaderAndCalculateDirectories() { + // First set the offset on the file, and on the bytes saved + m_saved_data_size = HEADER_SIZE; + // We know we will have at least Misc, SystemInfo, Modules, and ThreadList + // (corresponding memory list for stacks) And an additional memory list for + // non-stacks. + lldb_private::Target &target = m_process_sp->GetTarget(); + m_expected_directories = 6; + // Check if OS is linux and reserve directory space for all linux specific + // breakpad extension directories. + if (target.GetArchitecture().GetTriple().getOS() == + llvm::Triple::OSType::Linux) + m_expected_directories += 9; + + // Go through all of the threads and check for exceptions. + lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); + const uint32_t num_threads = thread_list.GetSize(); + for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { + ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); + StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); + if (stop_info_sp) { + const StopReason &stop_reason = stop_info_sp->GetStopReason(); + if (stop_reason == StopReason::eStopReasonException || + stop_reason == StopReason::eStopReasonSignal) + m_expected_directories++; + } + } + + m_saved_data_size += + m_expected_directories * sizeof(llvm::minidump::Directory); + Status error; + offset_t new_offset = m_core_file->SeekFromStart(m_saved_data_size); + if (new_offset != m_saved_data_size) + error.SetErrorStringWithFormat("Failed to fill in header and directory " + "sections. Written / Expected (%" PRIx64 + " / %" PRIx64 ")", + new_offset, m_saved_data_size); + + return error; +} + +Status MinidumpFileBuilder::AddDirectory(StreamType type, + uint64_t stream_size) { + // We explicitly cast type, an 32b enum, to uint32_t to avoid warnings. + Status error; + if (GetCurrentDataEndOffset() > UINT32_MAX) { + error.SetErrorStringWithFormat("Unable to add directory for stream type " + "%x, offset is greater then 32 bit limit.", + (uint32_t)type); + return error; + } + + if (m_directories.size() + 1 > m_expected_directories) { + error.SetErrorStringWithFormat( + "Unable to add directory for stream type %x, exceeded expected number " + "of directories %zu.", + (uint32_t)type, m_expected_directories); + return error; + } + LocationDescriptor loc; loc.DataSize = static_cast<llvm::support::ulittle32_t>(stream_size); // Stream will begin at the current end of data section @@ -46,11 +124,17 @@ void MinidumpFileBuilder::AddDirectory(StreamType type, size_t stream_size) { dir.Location = loc; m_directories.push_back(dir); + return error; } -Status MinidumpFileBuilder::AddSystemInfo(const llvm::Triple &target_triple) { +Status MinidumpFileBuilder::AddSystemInfo() { Status error; - AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); + const llvm::Triple &target_triple = + m_process_sp->GetTarget().GetArchitecture().GetTriple(); + error = + AddDirectory(StreamType::SystemInfo, sizeof(llvm::minidump::SystemInfo)); + if (error.Fail()) + return error; llvm::minidump::ProcessorArchitecture arch; switch (target_triple.getArch()) { @@ -154,8 +238,15 @@ Status WriteString(const std::string &to_write, llvm::Expected<uint64_t> getModuleFileSize(Target &target, const ModuleSP &mod) { - SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); + // JIT module has the same vm and file size. uint64_t SizeOfImage = 0; + if (mod->GetObjectFile()->CalculateType() == ObjectFile::Type::eTypeJIT) { + for (const auto §ion : *mod->GetObjectFile()->GetSectionList()) { + SizeOfImage += section->GetByteSize(); + } + return SizeOfImage; + } + SectionSP sect_sp = mod->GetObjectFile()->GetBaseAddress().GetSection(); if (!sect_sp) { return llvm::createStringError(std::errc::operation_not_supported, @@ -192,10 +283,11 @@ llvm::Expected<uint64_t> getModuleFileSize(Target &target, // single module. Additional data of variable length, such as module's names, // are stored just after the ModuleList stream. The llvm::minidump::Module // structures point to this helper data by global offset. -Status MinidumpFileBuilder::AddModuleList(Target &target) { +Status MinidumpFileBuilder::AddModuleList() { constexpr size_t minidump_module_size = sizeof(llvm::minidump::Module); Status error; + lldb_private::Target &target = m_process_sp->GetTarget(); const ModuleList &modules = target.GetImages(); llvm::support::ulittle32_t modules_count = static_cast<llvm::support::ulittle32_t>(modules.GetSize()); @@ -212,7 +304,9 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) { sizeof(llvm::support::ulittle32_t) + modules_count * minidump_module_size; // Adding directory describing this stream. - AddDirectory(StreamType::ModuleList, module_stream_size); + error = AddDirectory(StreamType::ModuleList, module_stream_size); + if (error.Fail()) + return error; m_data.AppendData(&modules_count, sizeof(llvm::support::ulittle32_t)); @@ -226,8 +320,13 @@ Status MinidumpFileBuilder::AddModuleList(Target &target) { std::string module_name = mod->GetSpecificationDescription(); auto maybe_mod_size = getModuleFileSize(target, mod); if (!maybe_mod_size) { - error.SetErrorStringWithFormat("Unable to get the size of module %s.", - module_name.c_str()); + llvm::Error mod_size_err = maybe_mod_size.takeError(); + llvm::handleAllErrors(std::move(mod_size_err), + [&](const llvm::ErrorInfoBase &E) { + error.SetErrorStringWithFormat( + "Unable to get the size of module %s: %s.", + module_name.c_str(), E.message().c_str()); + }); return error; } @@ -464,31 +563,32 @@ public: } }; -// Function returns start and size of the memory region that contains -// memory location pointed to by the current stack pointer. -llvm::Expected<std::pair<addr_t, addr_t>> -findStackHelper(const lldb::ProcessSP &process_sp, uint64_t rsp) { - MemoryRegionInfo range_info; - Status error = process_sp->GetMemoryRegionInfo(rsp, range_info); - // Skip failed memory region requests or any regions with no permissions. - if (error.Fail() || range_info.GetLLDBPermissions() == 0) - return llvm::createStringError( - std::errc::not_supported, - "unable to load stack segment of the process"); - - const addr_t addr = range_info.GetRange().GetRangeBase(); - const addr_t size = range_info.GetRange().GetByteSize(); - - if (size == 0) - return llvm::createStringError(std::errc::not_supported, - "stack segment of the process is empty"); - - return std::make_pair(addr, size); +Status MinidumpFileBuilder::FixThreadStacks() { + Status error; + // If we have anything in the heap flush it. + FlushBufferToDisk(); + m_core_file->SeekFromStart(m_thread_list_start); + for (auto &pair : m_thread_by_range_end) { + // The thread objects will get a new memory descriptor added + // When we are emitting the memory list and then we write it here + const llvm::minidump::Thread &thread = pair.second; + size_t bytes_to_write = sizeof(llvm::minidump::Thread); + size_t bytes_written = bytes_to_write; + error = m_core_file->Write(&thread, bytes_written); + if (error.Fail() || bytes_to_write != bytes_written) { + error.SetErrorStringWithFormat( + "Wrote incorrect number of bytes to minidump file. (written %zd/%zd)", + bytes_written, bytes_to_write); + return error; + } + } + + return error; } -Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { +Status MinidumpFileBuilder::AddThreadList() { constexpr size_t minidump_thread_size = sizeof(llvm::minidump::Thread); - lldb_private::ThreadList thread_list = process_sp->GetThreadList(); + lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); // size of the entire thread stream consists of: // number of threads and threads array @@ -496,28 +596,31 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { thread_list.GetSize() * minidump_thread_size; // save for the ability to set up RVA size_t size_before = GetCurrentDataEndOffset(); - - AddDirectory(StreamType::ThreadList, thread_stream_size); + Status error; + error = AddDirectory(StreamType::ThreadList, thread_stream_size); + if (error.Fail()) + return error; llvm::support::ulittle32_t thread_count = static_cast<llvm::support::ulittle32_t>(thread_list.GetSize()); m_data.AppendData(&thread_count, sizeof(llvm::support::ulittle32_t)); + // Take the offset after the thread count. + m_thread_list_start = GetCurrentDataEndOffset(); DataBufferHeap helper_data; const uint32_t num_threads = thread_list.GetSize(); - + Log *log = GetLog(LLDBLog::Object); for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); - Status error; if (!reg_ctx_sp) { error.SetErrorString("Unable to get the register context."); return error; } RegisterContext *reg_ctx = reg_ctx_sp.get(); - Target &target = process_sp->GetTarget(); + Target &target = m_process_sp->GetTarget(); const ArchSpec &arch = target.GetArchitecture(); ArchThreadContexts thread_context(arch.GetMachine()); if (!thread_context.prepareRegisterContext(reg_ctx)) { @@ -526,38 +629,18 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { arch.GetTriple().getArchName().str().c_str()); return error; } - uint64_t sp = reg_ctx->GetSP(); - auto expected_address_range = findStackHelper(process_sp, sp); - - if (!expected_address_range) { - consumeError(expected_address_range.takeError()); - error.SetErrorString("Unable to get the stack address."); - return error; - } - - std::pair<uint64_t, uint64_t> range = std::move(*expected_address_range); - uint64_t addr = range.first; - uint64_t size = range.second; - - auto data_up = std::make_unique<DataBufferHeap>(size, 0); - const size_t stack_bytes_read = - process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); - - if (error.Fail()) - return error; - LocationDescriptor stack_memory; - stack_memory.DataSize = - static_cast<llvm::support::ulittle32_t>(stack_bytes_read); - stack_memory.RVA = static_cast<llvm::support::ulittle32_t>( - size_before + thread_stream_size + helper_data.GetByteSize()); + uint64_t sp = reg_ctx->GetSP(); + MemoryRegionInfo sp_region; + m_process_sp->GetMemoryRegionInfo(sp, sp_region); + // Emit a blank descriptor MemoryDescriptor stack; - stack.StartOfMemoryRange = static_cast<llvm::support::ulittle64_t>(addr); - stack.Memory = stack_memory; - - helper_data.AppendData(data_up->GetBytes(), stack_bytes_read); - + LocationDescriptor empty_label; + empty_label.DataSize = 0; + empty_label.RVA = 0; + stack.Memory = empty_label; + stack.StartOfMemoryRange = 0; LocationDescriptor thread_context_memory_locator; thread_context_memory_locator.DataSize = static_cast<llvm::support::ulittle32_t>(thread_context.size()); @@ -566,6 +649,8 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { // Cache thie thread context memory so we can reuse for exceptions. m_tid_to_reg_ctx[thread_sp->GetID()] = thread_context_memory_locator; + LLDB_LOGF(log, "AddThreadList for thread %d: thread_context %zu bytes", + thread_idx, thread_context.size()); helper_data.AppendData(thread_context.data(), thread_context.size()); llvm::minidump::Thread t; @@ -577,16 +662,20 @@ Status MinidumpFileBuilder::AddThreadList(const lldb::ProcessSP &process_sp) { t.EnvironmentBlock = static_cast<llvm::support::ulittle64_t>(0); t.Stack = stack, t.Context = thread_context_memory_locator; + // We save off the stack object so we can circle back and clean it up. + m_thread_by_range_end[sp_region.GetRange().GetRangeEnd()] = t; m_data.AppendData(&t, sizeof(llvm::minidump::Thread)); } + LLDB_LOGF(log, "AddThreadList(): total helper_data %" PRIx64 " bytes", + helper_data.GetByteSize()); m_data.AppendData(helper_data.GetBytes(), helper_data.GetByteSize()); return Status(); } -void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { - lldb_private::ThreadList thread_list = process_sp->GetThreadList(); - +Status MinidumpFileBuilder::AddExceptions() { + lldb_private::ThreadList thread_list = m_process_sp->GetThreadList(); + Status error; const uint32_t num_threads = thread_list.GetSize(); for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx)); @@ -605,7 +694,10 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { if (add_exception) { constexpr size_t minidump_exception_size = sizeof(llvm::minidump::ExceptionStream); - AddDirectory(StreamType::Exception, minidump_exception_size); + error = AddDirectory(StreamType::Exception, minidump_exception_size); + if (error.Fail()) + return error; + StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); RegisterContextSP reg_ctx_sp(thread_sp->GetRegisterContext()); Exception exp_record = {}; @@ -633,63 +725,16 @@ void MinidumpFileBuilder::AddExceptions(const lldb::ProcessSP &process_sp) { m_data.AppendData(&exp_stream, minidump_exception_size); } } -} - -lldb_private::Status -MinidumpFileBuilder::AddMemoryList(const lldb::ProcessSP &process_sp, - lldb::SaveCoreStyle core_style) { - Status error; - Process::CoreFileMemoryRanges core_ranges; - error = process_sp->CalculateCoreFileSaveRanges(core_style, core_ranges); - if (error.Fail()) { - error.SetErrorString("Process doesn't support getting memory region info."); - return error; - } - - DataBufferHeap helper_data; - std::vector<MemoryDescriptor> mem_descriptors; - for (const auto &core_range : core_ranges) { - // Skip empty memory regions or any regions with no permissions. - if (core_range.range.empty() || core_range.lldb_permissions == 0) - continue; - const addr_t addr = core_range.range.start(); - const addr_t size = core_range.range.size(); - auto data_up = std::make_unique<DataBufferHeap>(size, 0); - const size_t bytes_read = - process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); - if (bytes_read == 0) - continue; - // We have a good memory region with valid bytes to store. - LocationDescriptor memory_dump; - memory_dump.DataSize = static_cast<llvm::support::ulittle32_t>(bytes_read); - memory_dump.RVA = - static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); - MemoryDescriptor memory_desc; - memory_desc.StartOfMemoryRange = - static_cast<llvm::support::ulittle64_t>(addr); - memory_desc.Memory = memory_dump; - mem_descriptors.push_back(memory_desc); - m_data.AppendData(data_up->GetBytes(), bytes_read); - } - - AddDirectory(StreamType::MemoryList, - sizeof(llvm::support::ulittle32_t) + - mem_descriptors.size() * - sizeof(llvm::minidump::MemoryDescriptor)); - llvm::support::ulittle32_t memory_ranges_num(mem_descriptors.size()); - - m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); - for (auto memory_descriptor : mem_descriptors) { - m_data.AppendData(&memory_descriptor, - sizeof(llvm::minidump::MemoryDescriptor)); - } return error; } -void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { - AddDirectory(StreamType::MiscInfo, - sizeof(lldb_private::minidump::MinidumpMiscInfo)); +lldb_private::Status MinidumpFileBuilder::AddMiscInfo() { + Status error; + error = AddDirectory(StreamType::MiscInfo, + sizeof(lldb_private::minidump::MinidumpMiscInfo)); + if (error.Fail()) + return error; lldb_private::minidump::MinidumpMiscInfo misc_info; misc_info.size = static_cast<llvm::support::ulittle32_t>( @@ -699,7 +744,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { misc_info.flags1 = static_cast<llvm::support::ulittle32_t>(0); lldb_private::ProcessInstanceInfo process_info; - process_sp->GetProcessInfo(process_info); + m_process_sp->GetProcessInfo(process_info); if (process_info.ProcessIDIsValid()) { // Set flags1 to reflect that PID is filled in misc_info.flags1 = @@ -711,6 +756,7 @@ void MinidumpFileBuilder::AddMiscInfo(const lldb::ProcessSP &process_sp) { m_data.AppendData(&misc_info, sizeof(lldb_private::minidump::MinidumpMiscInfo)); + return error; } std::unique_ptr<llvm::MemoryBuffer> @@ -721,15 +767,20 @@ getFileStreamHelper(const std::string &path) { return std::move(maybe_stream.get()); } -void MinidumpFileBuilder::AddLinuxFileStreams( - const lldb::ProcessSP &process_sp) { +Status MinidumpFileBuilder::AddLinuxFileStreams() { + Status error; + // No-op if we are not on linux. + if (m_process_sp->GetTarget().GetArchitecture().GetTriple().getOS() != + llvm::Triple::Linux) + return error; + std::vector<std::pair<StreamType, std::string>> files_with_stream_types = { {StreamType::LinuxCPUInfo, "/proc/cpuinfo"}, {StreamType::LinuxLSBRelease, "/etc/lsb-release"}, }; lldb_private::ProcessInstanceInfo process_info; - process_sp->GetProcessInfo(process_info); + m_process_sp->GetProcessInfo(process_info); if (process_info.ProcessIDIsValid()) { lldb::pid_t pid = process_info.GetProcessID(); std::string pid_str = std::to_string(pid); @@ -758,16 +809,94 @@ void MinidumpFileBuilder::AddLinuxFileStreams( size_t size = memory_buffer->getBufferSize(); if (size == 0) continue; - AddDirectory(stream, size); + error = AddDirectory(stream, size); + if (error.Fail()) + return error; m_data.AppendData(memory_buffer->getBufferStart(), size); } } + + return error; } -Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { - constexpr size_t header_size = sizeof(llvm::minidump::Header); - constexpr size_t directory_size = sizeof(llvm::minidump::Directory); +Status MinidumpFileBuilder::AddMemoryList(SaveCoreStyle core_style) { + Status error; + + // We first save the thread stacks to ensure they fit in the first UINT32_MAX + // bytes of the core file. Thread structures in minidump files can only use + // 32 bit memory descriptiors, so we emit them first to ensure the memory is + // in accessible with a 32 bit offset. + Process::CoreFileMemoryRanges ranges_32; + Process::CoreFileMemoryRanges ranges_64; + error = m_process_sp->CalculateCoreFileSaveRanges( + SaveCoreStyle::eSaveCoreStackOnly, ranges_32); + if (error.Fail()) + return error; + + // Calculate totalsize including the current offset. + uint64_t total_size = GetCurrentDataEndOffset(); + total_size += ranges_32.size() * sizeof(llvm::minidump::MemoryDescriptor); + std::unordered_set<addr_t> stack_start_addresses; + for (const auto &core_range : ranges_32) { + stack_start_addresses.insert(core_range.range.start()); + total_size += core_range.range.size(); + } + + if (total_size >= UINT32_MAX) { + error.SetErrorStringWithFormat("Unable to write minidump. Stack memory " + "exceeds 32b limit. (Num Stacks %zu)", + ranges_32.size()); + return error; + } + + Process::CoreFileMemoryRanges all_core_memory_ranges; + if (core_style != SaveCoreStyle::eSaveCoreStackOnly) { + error = m_process_sp->CalculateCoreFileSaveRanges(core_style, + all_core_memory_ranges); + if (error.Fail()) + return error; + } + // After saving the stacks, we start packing as much as we can into 32b. + // We apply a generous padding here so that the Directory, MemoryList and + // Memory64List sections all begin in 32b addressable space. + // Then anything overflow extends into 64b addressable space. + // All core memeroy ranges will either container nothing on stacks only + // or all the memory ranges including stacks + if (!all_core_memory_ranges.empty()) + total_size += + 256 + (all_core_memory_ranges.size() - stack_start_addresses.size()) * + sizeof(llvm::minidump::MemoryDescriptor_64); + + for (const auto &core_range : all_core_memory_ranges) { + const addr_t range_size = core_range.range.size(); + if (stack_start_addresses.count(core_range.range.start()) > 0) + // Don't double save stacks. + continue; + + if (total_size + range_size < UINT32_MAX) { + ranges_32.push_back(core_range); + total_size += range_size; + } else { + ranges_64.push_back(core_range); + } + } + + error = AddMemoryList_32(ranges_32); + if (error.Fail()) + return error; + + // Add the remaining memory as a 64b range. + if (!ranges_64.empty()) { + error = AddMemoryList_64(ranges_64); + if (error.Fail()) + return error; + } + + return FixThreadStacks(); +} + +Status MinidumpFileBuilder::DumpHeader() const { // write header llvm::minidump::Header header; header.Signature = static_cast<llvm::support::ulittle32_t>( @@ -775,9 +904,10 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { header.Version = static_cast<llvm::support::ulittle32_t>( llvm::minidump::Header::MagicVersion); header.NumberOfStreams = - static_cast<llvm::support::ulittle32_t>(GetDirectoriesNum()); + static_cast<llvm::support::ulittle32_t>(m_directories.size()); + // We write the directories right after the header. header.StreamDirectoryRVA = - static_cast<llvm::support::ulittle32_t>(GetCurrentDataEndOffset()); + static_cast<llvm::support::ulittle32_t>(HEADER_SIZE); header.Checksum = static_cast<llvm::support::ulittle32_t>( 0u), // not used in most of the writers header.TimeDateStamp = @@ -788,36 +918,35 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { Status error; size_t bytes_written; - bytes_written = header_size; - error = core_file->Write(&header, bytes_written); - if (error.Fail() || bytes_written != header_size) { - if (bytes_written != header_size) + m_core_file->SeekFromStart(0); + bytes_written = HEADER_SIZE; + error = m_core_file->Write(&header, bytes_written); + if (error.Fail() || bytes_written != HEADER_SIZE) { + if (bytes_written != HEADER_SIZE) error.SetErrorStringWithFormat( - "unable to write the header (written %zd/%zd)", bytes_written, - header_size); + "Unable to write the minidump header (written %zd/%zd)", + bytes_written, HEADER_SIZE); return error; } + return error; +} - // write data - bytes_written = m_data.GetByteSize(); - error = core_file->Write(m_data.GetBytes(), bytes_written); - if (error.Fail() || bytes_written != m_data.GetByteSize()) { - if (bytes_written != m_data.GetByteSize()) - error.SetErrorStringWithFormat( - "unable to write the data (written %zd/%" PRIu64 ")", bytes_written, - m_data.GetByteSize()); - return error; - } +offset_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { + return m_data.GetByteSize() + m_saved_data_size; +} - // write directories +Status MinidumpFileBuilder::DumpDirectories() const { + Status error; + size_t bytes_written; + m_core_file->SeekFromStart(HEADER_SIZE); for (const Directory &dir : m_directories) { - bytes_written = directory_size; - error = core_file->Write(&dir, bytes_written); - if (error.Fail() || bytes_written != directory_size) { - if (bytes_written != directory_size) + bytes_written = DIRECTORY_SIZE; + error = m_core_file->Write(&dir, bytes_written); + if (error.Fail() || bytes_written != DIRECTORY_SIZE) { + if (bytes_written != DIRECTORY_SIZE) error.SetErrorStringWithFormat( "unable to write the directory (written %zd/%zd)", bytes_written, - directory_size); + DIRECTORY_SIZE); return error; } } @@ -825,10 +954,254 @@ Status MinidumpFileBuilder::Dump(lldb::FileUP &core_file) const { return error; } -size_t MinidumpFileBuilder::GetDirectoriesNum() const { - return m_directories.size(); +static uint64_t +GetLargestRangeSize(const Process::CoreFileMemoryRanges &ranges) { + uint64_t max_size = 0; + for (const auto &core_range : ranges) + max_size = std::max(max_size, core_range.range.size()); + return max_size; +} + +Status +MinidumpFileBuilder::AddMemoryList_32(Process::CoreFileMemoryRanges &ranges) { + std::vector<MemoryDescriptor> descriptors; + Status error; + if (ranges.size() == 0) + return error; + + Log *log = GetLog(LLDBLog::Object); + size_t region_index = 0; + auto data_up = + std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0); + for (const auto &core_range : ranges) { + // Take the offset before we write. + const offset_t offset_for_data = GetCurrentDataEndOffset(); + const addr_t addr = core_range.range.start(); + const addr_t size = core_range.range.size(); + const addr_t end = core_range.range.end(); + + LLDB_LOGF(log, + "AddMemoryList %zu/%zu reading memory for region " + "(%" PRIx64 " bytes) [%" PRIx64 ", %" PRIx64 ")", + region_index, ranges.size(), size, addr, addr + size); + ++region_index; + + const size_t bytes_read = + m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); + if (error.Fail() || bytes_read == 0) { + LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s", + bytes_read, error.AsCString()); + // Just skip sections with errors or zero bytes in 32b mode + continue; + } else if (bytes_read != size) { + LLDB_LOGF( + log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", + addr, size); + } + + MemoryDescriptor descriptor; + descriptor.StartOfMemoryRange = + static_cast<llvm::support::ulittle64_t>(addr); + descriptor.Memory.DataSize = + static_cast<llvm::support::ulittle32_t>(bytes_read); + descriptor.Memory.RVA = + static_cast<llvm::support::ulittle32_t>(offset_for_data); + descriptors.push_back(descriptor); + if (m_thread_by_range_end.count(end) > 0) + m_thread_by_range_end[end].Stack = descriptor; + + // Add the data to the buffer, flush as needed. + error = AddData(data_up->GetBytes(), bytes_read); + if (error.Fail()) + return error; + } + + // Add a directory that references this list + // With a size of the number of ranges as a 32 bit num + // And then the size of all the ranges + error = AddDirectory(StreamType::MemoryList, + sizeof(llvm::support::ulittle32_t) + + descriptors.size() * + sizeof(llvm::minidump::MemoryDescriptor)); + if (error.Fail()) + return error; + + llvm::support::ulittle32_t memory_ranges_num = + static_cast<llvm::support::ulittle32_t>(descriptors.size()); + m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle32_t)); + // For 32b we can get away with writing off the descriptors after the data. + // This means no cleanup loop needed. + m_data.AppendData(descriptors.data(), + descriptors.size() * sizeof(MemoryDescriptor)); + + return error; +} + +Status +MinidumpFileBuilder::AddMemoryList_64(Process::CoreFileMemoryRanges &ranges) { + Status error; + if (ranges.empty()) + return error; + + error = AddDirectory(StreamType::Memory64List, + (sizeof(llvm::support::ulittle64_t) * 2) + + ranges.size() * + sizeof(llvm::minidump::MemoryDescriptor_64)); + if (error.Fail()) + return error; + + llvm::support::ulittle64_t memory_ranges_num = + static_cast<llvm::support::ulittle64_t>(ranges.size()); + m_data.AppendData(&memory_ranges_num, sizeof(llvm::support::ulittle64_t)); + // Capture the starting offset for all the descriptors so we can clean them up + // if needed. + offset_t starting_offset = + GetCurrentDataEndOffset() + sizeof(llvm::support::ulittle64_t); + // The base_rva needs to start after the directories, which is right after + // this 8 byte variable. + offset_t base_rva = + starting_offset + + (ranges.size() * sizeof(llvm::minidump::MemoryDescriptor_64)); + llvm::support::ulittle64_t memory_ranges_base_rva = + static_cast<llvm::support::ulittle64_t>(base_rva); + m_data.AppendData(&memory_ranges_base_rva, + sizeof(llvm::support::ulittle64_t)); + + bool cleanup_required = false; + std::vector<MemoryDescriptor_64> descriptors; + // Enumerate the ranges and create the memory descriptors so we can append + // them first + for (const auto core_range : ranges) { + // Add the space required to store the memory descriptor + MemoryDescriptor_64 memory_desc; + memory_desc.StartOfMemoryRange = + static_cast<llvm::support::ulittle64_t>(core_range.range.start()); + memory_desc.DataSize = + static_cast<llvm::support::ulittle64_t>(core_range.range.size()); + descriptors.push_back(memory_desc); + // Now write this memory descriptor to the buffer. + m_data.AppendData(&memory_desc, sizeof(MemoryDescriptor_64)); + } + + Log *log = GetLog(LLDBLog::Object); + size_t region_index = 0; + auto data_up = + std::make_unique<DataBufferHeap>(GetLargestRangeSize(ranges), 0); + for (const auto &core_range : ranges) { + const addr_t addr = core_range.range.start(); + const addr_t size = core_range.range.size(); + + LLDB_LOGF(log, + "AddMemoryList_64 %zu/%zu reading memory for region " + "(%" PRIx64 "bytes) " + "[%" PRIx64 ", %" PRIx64 ")", + region_index, ranges.size(), size, addr, addr + size); + ++region_index; + + const size_t bytes_read = + m_process_sp->ReadMemory(addr, data_up->GetBytes(), size, error); + if (error.Fail()) { + LLDB_LOGF(log, "Failed to read memory region. Bytes read: %zu, error: %s", + bytes_read, error.AsCString()); + error.Clear(); + cleanup_required = true; + descriptors[region_index].DataSize = 0; + } + if (bytes_read != size) { + LLDB_LOGF( + log, "Memory region at: %" PRIx64 " failed to read %" PRIx64 " bytes", + addr, size); + cleanup_required = true; + descriptors[region_index].DataSize = bytes_read; + } + + // Add the data to the buffer, flush as needed. + error = AddData(data_up->GetBytes(), bytes_read); + if (error.Fail()) + return error; + } + + // Early return if there is no cleanup needed. + if (!cleanup_required) { + return error; + } else { + // Flush to disk we can make the fixes in place. + FlushBufferToDisk(); + // Fixup the descriptors that were not read correctly. + m_core_file->SeekFromStart(starting_offset); + size_t bytes_written = sizeof(MemoryDescriptor_64) * descriptors.size(); + error = m_core_file->Write(descriptors.data(), bytes_written); + if (error.Fail() || + bytes_written != sizeof(MemoryDescriptor_64) * descriptors.size()) { + error.SetErrorStringWithFormat( + "unable to write the memory descriptors (written %zd/%zd)", + bytes_written, sizeof(MemoryDescriptor_64) * descriptors.size()); + } + + return error; + } +} + +Status MinidumpFileBuilder::AddData(const void *data, uint64_t size) { + // This should also get chunked, because worst case we copy over a big + // object / memory range, say 5gb. In that case, we'd have to allocate 10gb + // 5 gb for the buffer we're copying from, and then 5gb for the buffer we're + // copying to. Which will be short lived and immedaitely go to disk, the goal + // here is to limit the number of bytes we need to host in memory at any given + // time. + m_data.AppendData(data, size); + if (m_data.GetByteSize() > MAX_WRITE_CHUNK_SIZE) + return FlushBufferToDisk(); + + return Status(); } -size_t MinidumpFileBuilder::GetCurrentDataEndOffset() const { - return sizeof(llvm::minidump::Header) + m_data.GetByteSize(); +Status MinidumpFileBuilder::FlushBufferToDisk() { + Status error; + // Set the stream to it's end. + m_core_file->SeekFromStart(m_saved_data_size); + addr_t starting_size = m_data.GetByteSize(); + addr_t remaining_bytes = starting_size; + offset_t offset = 0; + + while (remaining_bytes > 0) { + size_t bytes_written = remaining_bytes; + // We don't care how many bytes we wrote unless we got an error + // so just decrement the remaining bytes. + error = m_core_file->Write(m_data.GetBytes() + offset, bytes_written); + if (error.Fail()) { + error.SetErrorStringWithFormat( + "Wrote incorrect number of bytes to minidump file. (written %" PRIx64 + "/%" PRIx64 ")", + starting_size - remaining_bytes, starting_size); + return error; + } + + offset += bytes_written; + remaining_bytes -= bytes_written; + } + + m_saved_data_size += starting_size; + m_data.Clear(); + return error; +} + +Status MinidumpFileBuilder::DumpFile() { + Status error; + // If anything is left unsaved, dump it. + error = FlushBufferToDisk(); + if (error.Fail()) + return error; + + // Overwrite the header which we filled in earlier. + error = DumpHeader(); + if (error.Fail()) + return error; + + // Overwrite the space saved for directories + error = DumpDirectories(); + if (error.Fail()) + return error; + + return error; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h index b2e984191983..20564e0661f2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.h @@ -17,12 +17,20 @@ #define LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H #include <cstddef> +#include <cstdint> #include <map> +#include <unordered_map> +#include <utility> +#include <variant> +#include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Status.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" +#include "llvm/BinaryFormat/Minidump.h" #include "llvm/Object/Minidump.h" // Write std::string to minidump in the UTF16 format(with null termination char) @@ -36,11 +44,39 @@ lldb_private::Status WriteString(const std::string &to_write, /// Minidump writer for Linux /// /// This class provides a Minidump writer that is able to -/// snapshot the current process state. For the whole time, it stores all -/// the data on heap. +/// snapshot the current process state. +/// +/// Minidumps are a Microsoft format for dumping process state. +/// This class constructs the minidump on disk starting with +/// Headers and Directories are written at the top of the file, +/// with the amount of bytes being precalculates before any writing takes place +/// Then the smaller data sections are written +/// SystemInfo, ModuleList, Misc Info. +/// Then Threads are emitted, threads are the first section that needs to be +/// 'fixed up' this happens when later we emit the memory stream, we identify if +/// that stream is the expected stack, and if so we update the stack with the +/// current RVA. Lastly the Memory lists are added. For Memory List, this will +/// contain everything that can fit within 4.2gb. MemoryList has it's +/// descriptors written at the end so it cannot be allowed to overflow. +/// +/// Memory64List is a special case where it has to be begin before 4.2gb but can +/// expand forever The difference in Memory64List is there are no RVA's and all +/// the addresses are figured out by starting at the base RVA, and adding the +/// antecedent memory sections. +/// +/// Because Memory64List can be arbitrarily large, this class has to write +/// chunks to disk this means we have to precalculate the descriptors and write +/// them first, and if we encounter any error, or are unable to read the same +/// number of bytes we have to go back and update them on disk. +/// +/// And as the last step, after all the directories have been added, we go back +/// to the top of the file to fill in the header and the redirectory sections +/// that we preallocated. class MinidumpFileBuilder { public: - MinidumpFileBuilder() = default; + MinidumpFileBuilder(lldb::FileUP &&core_file, + const lldb::ProcessSP &process_sp) + : m_process_sp(process_sp), m_core_file(std::move(core_file)){}; MinidumpFileBuilder(const MinidumpFileBuilder &) = delete; MinidumpFileBuilder &operator=(const MinidumpFileBuilder &) = delete; @@ -50,48 +86,84 @@ public: ~MinidumpFileBuilder() = default; + // This method only calculates the amount of bytes the header and directories + // will take up. It does not write the directories or headers. This function + // must be called with a followup to fill in the data. + lldb_private::Status AddHeaderAndCalculateDirectories(); // Add SystemInfo stream, used for storing the most basic information // about the system, platform etc... - lldb_private::Status AddSystemInfo(const llvm::Triple &target_triple); + lldb_private::Status AddSystemInfo(); // Add ModuleList stream, containing information about all loaded modules // at the time of saving minidump. - lldb_private::Status AddModuleList(lldb_private::Target &target); + lldb_private::Status AddModuleList(); // Add ThreadList stream, containing information about all threads running // at the moment of core saving. Contains information about thread // contexts. - lldb_private::Status AddThreadList(const lldb::ProcessSP &process_sp); + lldb_private::Status AddThreadList(); // Add Exception streams for any threads that stopped with exceptions. - void AddExceptions(const lldb::ProcessSP &process_sp); + lldb_private::Status AddExceptions(); // Add MemoryList stream, containing dumps of important memory segments - lldb_private::Status AddMemoryList(const lldb::ProcessSP &process_sp, - lldb::SaveCoreStyle core_style); + lldb_private::Status AddMemoryList(lldb::SaveCoreStyle core_style); // Add MiscInfo stream, mainly providing ProcessId - void AddMiscInfo(const lldb::ProcessSP &process_sp); + lldb_private::Status AddMiscInfo(); // Add informative files about a Linux process - void AddLinuxFileStreams(const lldb::ProcessSP &process_sp); - // Dump the prepared data into file. In case of the failure data are - // intact. - lldb_private::Status Dump(lldb::FileUP &core_file) const; - // Returns the current number of directories(streams) that have been so far - // created. This number of directories will be dumped when calling Dump() - size_t GetDirectoriesNum() const; + lldb_private::Status AddLinuxFileStreams(); + + // Run cleanup and write all remaining bytes to file + lldb_private::Status DumpFile(); private: + // Add data to the end of the buffer, if the buffer exceeds the flush level, + // trigger a flush. + lldb_private::Status AddData(const void *data, uint64_t size); + // Add MemoryList stream, containing dumps of important memory segments + lldb_private::Status + AddMemoryList_64(lldb_private::Process::CoreFileMemoryRanges &ranges); + lldb_private::Status + AddMemoryList_32(lldb_private::Process::CoreFileMemoryRanges &ranges); + // Update the thread list on disk with the newly emitted stack RVAs. + lldb_private::Status FixThreadStacks(); + lldb_private::Status FlushBufferToDisk(); + + lldb_private::Status DumpHeader() const; + lldb_private::Status DumpDirectories() const; // Add directory of StreamType pointing to the current end of the prepared // file with the specified size. - void AddDirectory(llvm::minidump::StreamType type, size_t stream_size); - size_t GetCurrentDataEndOffset() const; - - // Stores directories to later put them at the end of minidump file + lldb_private::Status AddDirectory(llvm::minidump::StreamType type, + uint64_t stream_size); + lldb::offset_t GetCurrentDataEndOffset() const; + // Stores directories to fill in later std::vector<llvm::minidump::Directory> m_directories; + // When we write off the threads for the first time, we need to clean them up + // and give them the correct RVA once we write the stack memory list. + // We save by the end because we only take from the stack pointer up + // So the saved off range base can differ from the memory region the stack + // pointer is in. + std::unordered_map<lldb::addr_t, llvm::minidump::Thread> + m_thread_by_range_end; // Main data buffer consisting of data without the minidump header and // directories lldb_private::DataBufferHeap m_data; + lldb::ProcessSP m_process_sp; + + size_t m_expected_directories = 0; + uint64_t m_saved_data_size = 0; + lldb::offset_t m_thread_list_start = 0; + // We set the max write amount to 128 mb, this is arbitrary + // but we want to try to keep the size of m_data small + // and we will only exceed a 128 mb buffer if we get a memory region + // that is larger than 128 mb. + static constexpr size_t MAX_WRITE_CHUNK_SIZE = (1024 * 1024 * 128); + + static constexpr size_t HEADER_SIZE = sizeof(llvm::minidump::Header); + static constexpr size_t DIRECTORY_SIZE = sizeof(llvm::minidump::Directory); // More that one place can mention the register thread context locations, // so when we emit the thread contents, remember where it is so we don't have // to duplicate it in the exception data. - std::map<lldb::tid_t, llvm::minidump::LocationDescriptor> m_tid_to_reg_ctx; + std::unordered_map<lldb::tid_t, llvm::minidump::LocationDescriptor> + m_tid_to_reg_ctx; + lldb::FileUP m_core_file; }; #endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_MINIDUMP_MINIDUMPFILEBUILDER_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp index fe609c7f3d20..faa144bfb5f6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.cpp @@ -14,6 +14,8 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "llvm/Support/FileSystem.h" @@ -54,57 +56,82 @@ size_t ObjectFileMinidump::GetModuleSpecifications( } bool ObjectFileMinidump::SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error) { - // Set default core style if it isn't set. + // Output file and process_sp are both checked in PluginManager::SaveCore. + assert(options.GetOutputFile().has_value()); + assert(process_sp); + + // Minidump defaults to stacks only. + SaveCoreStyle core_style = options.GetStyle(); if (core_style == SaveCoreStyle::eSaveCoreUnspecified) core_style = SaveCoreStyle::eSaveCoreStackOnly; - if (!process_sp) + llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open( + options.GetOutputFile().value(), + File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); + if (!maybe_core_file) { + error = maybe_core_file.takeError(); return false; + } + MinidumpFileBuilder builder(std::move(maybe_core_file.get()), process_sp); - MinidumpFileBuilder builder; - - Target &target = process_sp->GetTarget(); - - error = builder.AddSystemInfo(target.GetArchitecture().GetTriple()); - if (error.Fail()) + Log *log = GetLog(LLDBLog::Object); + error = builder.AddHeaderAndCalculateDirectories(); + if (error.Fail()) { + LLDB_LOGF(log, "AddHeaderAndCalculateDirectories failed: %s", + error.AsCString()); + return false; + }; + error = builder.AddSystemInfo(); + if (error.Fail()) { + LLDB_LOGF(log, "AddSystemInfo failed: %s", error.AsCString()); return false; + } - error = builder.AddModuleList(target); - if (error.Fail()) + error = builder.AddModuleList(); + if (error.Fail()) { + LLDB_LOGF(log, "AddModuleList failed: %s", error.AsCString()); + return false; + } + error = builder.AddMiscInfo(); + if (error.Fail()) { + LLDB_LOGF(log, "AddMiscInfo failed: %s", error.AsCString()); return false; + } - builder.AddMiscInfo(process_sp); + error = builder.AddThreadList(); + if (error.Fail()) { + LLDB_LOGF(log, "AddThreadList failed: %s", error.AsCString()); + return false; + } - error = builder.AddThreadList(process_sp); - if (error.Fail()) + error = builder.AddLinuxFileStreams(); + if (error.Fail()) { + LLDB_LOGF(log, "AddLinuxFileStreams failed: %s", error.AsCString()); return false; + } // Add any exceptions but only if there are any in any threads. - builder.AddExceptions(process_sp); - - error = builder.AddMemoryList(process_sp, core_style); - if (error.Fail()) + error = builder.AddExceptions(); + if (error.Fail()) { + LLDB_LOGF(log, "AddExceptions failed: %s", error.AsCString()); return false; - - if (target.GetArchitecture().GetTriple().getOS() == - llvm::Triple::OSType::Linux) { - builder.AddLinuxFileStreams(process_sp); } - llvm::Expected<lldb::FileUP> maybe_core_file = FileSystem::Instance().Open( - outfile, File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate); - if (!maybe_core_file) { - error = maybe_core_file.takeError(); + // Note: add memory HAS to be the last thing we do. It can overflow into 64b + // land and many RVA's only support 32b + error = builder.AddMemoryList(core_style); + if (error.Fail()) { + LLDB_LOGF(log, "AddMemoryList failed: %s", error.AsCString()); return false; } - lldb::FileUP core_file = std::move(maybe_core_file.get()); - error = builder.Dump(core_file); - if (error.Fail()) + error = builder.DumpFile(); + if (error.Fail()) { + LLDB_LOGF(log, "DumpFile failed: %s", error.AsCString()); return false; + } return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h index b5c40445fe74..0cd31a0e482d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h +++ b/contrib/llvm-project/lldb/source/Plugins/ObjectFile/Minidump/ObjectFileMinidump.h @@ -55,8 +55,7 @@ public: // Saves dump in Minidump file format static bool SaveCore(const lldb::ProcessSP &process_sp, - const lldb_private::FileSpec &outfile, - lldb::SaveCoreStyle &core_style, + const lldb_private::SaveCoreOptions &options, lldb_private::Status &error); private: diff --git a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 81ee7e328b6c..e026ffefd645 100644 --- a/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -372,7 +372,7 @@ lldb::ThreadSP OperatingSystemPython::CreateThread(lldb::tid_t tid, std::vector<bool> core_used_map; if (thread_info_dict) { - ThreadList core_threads(m_process); + ThreadList core_threads(*m_process); ThreadList &thread_list = m_process->GetThreadList(); bool did_create = false; ThreadSP thread_sp( diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index b4f1b76c39db..588b19dac616 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -678,8 +678,8 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, loaded_image->Clear(); std::string path; - path = remote_file.GetPath(); - + path = remote_file.GetPath(false); + ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); if (!thread_sp) { error.SetErrorString("dlopen error: no thread available to call dlopen."); diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 88f1ad15b6b4..4684947ede20 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -684,6 +684,14 @@ Status PlatformRemoteGDBServer::RunShellCommand( signo_ptr, command_output, timeout); } +llvm::ErrorOr<llvm::MD5::MD5Result> +PlatformRemoteGDBServer::CalculateMD5(const FileSpec &file_spec) { + if (!IsConnected()) + return std::make_error_code(std::errc::not_connected); + + return m_gdb_client_up->CalculateMD5(file_spec); +} + void PlatformRemoteGDBServer::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 638f7db5ef80..0ae1f3cb4199 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/contrib/llvm-project/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -146,6 +146,9 @@ public: void CalculateTrapHandlerSymbolNames() override; + llvm::ErrorOr<llvm::MD5::MD5Result> + CalculateMD5(const FileSpec &file_spec) override; + const lldb::UnixSignalsSP &GetRemoteUnixSignals() override; size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp index 19e0986ace31..064bddd37052 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -48,20 +48,38 @@ static Status EnsureFDFlags(int fd, int flags) { return error; } +static Status CanTrace() { + int proc_debug, ret; + size_t len = sizeof(proc_debug); + ret = ::sysctlbyname("security.bsd.unprivileged_proc_debug", &proc_debug, + &len, nullptr, 0); + if (ret != 0) + return Status("sysctlbyname() security.bsd.unprivileged_proc_debug failed"); + + if (proc_debug < 1) + return Status( + "process debug disabled by security.bsd.unprivileged_proc_debug oid"); + + return {}; +} + // Public Static Methods llvm::Expected<std::unique_ptr<NativeProcessProtocol>> NativeProcessFreeBSD::Manager::Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate) { Log *log = GetLog(POSIXLog::Process); - Status status; + ::pid_t pid = ProcessLauncherPosixFork() .LaunchProcess(launch_info, status) .GetProcessId(); LLDB_LOG(log, "pid = {0:x}", pid); if (status.Fail()) { LLDB_LOG(log, "failed to launch process: {0}", status); + auto error = CanTrace(); + if (error.Fail()) + return error.ToError(); return status.ToError(); } @@ -392,8 +410,11 @@ Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, ret = ptrace(req, static_cast<::pid_t>(pid), static_cast<caddr_t>(addr), data); - if (ret == -1) - error.SetErrorToErrno(); + if (ret == -1) { + error = CanTrace(); + if (error.Success()) + error.SetErrorToErrno(); + } if (result) *result = ret; @@ -707,8 +728,12 @@ Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) { Status error = PopulateMemoryRegionCache(); - if (error.Fail()) + if (error.Fail()) { + auto status = CanTrace(); + if (status.Fail()) + return status; return error; + } FileSpec module_file_spec(module_path); FileSystem::Instance().Resolve(module_file_spec); @@ -729,8 +754,12 @@ NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) { load_addr = LLDB_INVALID_ADDRESS; Status error = PopulateMemoryRegionCache(); - if (error.Fail()) + if (error.Fail()) { + auto status = CanTrace(); + if (status.Fail()) + return status; return error; + } FileSpec file(file_name); for (const auto &it : m_mem_region_cache) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h index 0000484beac9..b7f659ef24de 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h @@ -9,14 +9,13 @@ #ifndef lldb_NativeRegisterContextFreeBSD_h #define lldb_NativeRegisterContextFreeBSD_h -#include "lldb/Host/common/NativeThreadProtocol.h" - #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" namespace lldb_private { namespace process_freebsd { class NativeProcessFreeBSD; +class NativeThreadFreeBSD; class NativeRegisterContextFreeBSD : public virtual NativeRegisterContextRegisterInfo { @@ -28,7 +27,7 @@ public: // executable. static NativeRegisterContextFreeBSD * CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeThreadFreeBSD &native_thread); virtual llvm::Error CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp index 2c5017664387..f19085600d6c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp @@ -29,12 +29,12 @@ using namespace lldb_private::process_freebsd; NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread); } NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) : NativeRegisterContextRegisterInfo( native_thread, new RegisterInfoPOSIX_arm(target_arch)) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp index 9db5970af653..28ea8b7ac118 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -16,6 +16,7 @@ #include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" // clang-format off @@ -28,14 +29,29 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_freebsd; +// A NativeRegisterContext is constructed per thread, but all threads' registers +// will contain the same fields. Therefore this mutex prevents each instance +// competing with the other, and subsequent instances from having to detect the +// fields all over again. +static std::mutex g_register_flags_detector_mutex; +static Arm64RegisterFlagsDetector g_register_flags_detector; + NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { + std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex); + if (!g_register_flags_detector.HasDetected()) { + NativeProcessFreeBSD &process = native_thread.GetProcess(); + g_register_flags_detector.DetectFields( + process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0), + process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0)); + } + return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); } NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) : NativeRegisterContextRegisterInfo( native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0)) #ifdef LLDB_HAS_FREEBSD_WATCHPOINT @@ -43,6 +59,10 @@ NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( m_read_dbreg(false) #endif { + g_register_flags_detector.UpdateRegisterInfo( + GetRegisterInfoInterface().GetRegisterInfo(), + GetRegisterInfoInterface().GetRegisterCount()); + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h index 799209e26e86..ba876006c6c5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h @@ -37,7 +37,7 @@ class NativeRegisterContextFreeBSD_arm64 public NativeRegisterContextDBReg_arm64 { public: NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeThreadFreeBSD &native_thread); uint32_t GetRegisterSetCount() const override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp index 0349f13945e3..090d0f3802c3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp @@ -30,12 +30,12 @@ using namespace lldb_private::process_freebsd; NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread); } NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) : NativeRegisterContextRegisterInfo( native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp index bdb57251f706..fd5eb1ee2a1c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp @@ -67,7 +67,7 @@ static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = { NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread); } @@ -83,7 +83,7 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) : NativeRegisterContextRegisterInfo( native_thread, CreateRegisterInfoInterface(target_arch)) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp index f4171a134aeb..5eed2d02b0a8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp @@ -237,7 +237,7 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) { return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread); } @@ -258,7 +258,7 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + const ArchSpec &target_arch, NativeThreadFreeBSD &native_thread) : NativeRegisterContextRegisterInfo( native_thread, CreateRegisterInfoInterface(target_arch)), NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h index 54ec9fc154ca..a522d850cb37 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h @@ -38,7 +38,7 @@ class NativeRegisterContextFreeBSD_x86_64 public NativeRegisterContextDBReg_x86 { public: NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeThreadFreeBSD &native_thread); uint32_t GetRegisterSetCount() const override; const RegisterSet *GetRegisterSet(uint32_t set_index) const override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp index 449ec27e0da8..a0de7751c7e5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp @@ -316,6 +316,10 @@ NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { return s; } +NativeProcessFreeBSD &NativeThreadFreeBSD::GetProcess() { + return static_cast<NativeProcessFreeBSD &>(m_process); +} + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> NativeThreadFreeBSD::GetSiginfo() const { Log *log = GetLog(POSIXLog::Process); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h index 6294a7a70963..edfb07658e19 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h @@ -47,6 +47,8 @@ public: Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + NativeProcessFreeBSD &GetProcess(); + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> GetSiginfo() const override; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp index 0019b4d65f15..635f99b4467d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.cpp @@ -32,7 +32,7 @@ namespace { class ProcessFreeBSDKernelFVC : public ProcessFreeBSDKernel { public: ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, lldb::ListenerSP listener, - fvc_t *fvc); + fvc_t *fvc, const FileSpec &core_file); ~ProcessFreeBSDKernelFVC(); @@ -50,7 +50,7 @@ private: class ProcessFreeBSDKernelKVM : public ProcessFreeBSDKernel { public: ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, lldb::ListenerSP listener, - kvm_t *fvc); + kvm_t *fvc, const FileSpec &core_file); ~ProcessFreeBSDKernelKVM(); @@ -67,8 +67,9 @@ private: } // namespace ProcessFreeBSDKernel::ProcessFreeBSDKernel(lldb::TargetSP target_sp, - ListenerSP listener_sp) - : PostMortemProcess(target_sp, listener_sp) {} + ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, ListenerSP listener_sp, @@ -82,7 +83,7 @@ lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, crash_file->GetPath().c_str(), nullptr, nullptr, nullptr); if (fvc) return std::make_shared<ProcessFreeBSDKernelFVC>(target_sp, listener_sp, - fvc); + fvc, *crash_file); #endif #if defined(__FreeBSD__) @@ -91,7 +92,7 @@ lldb::ProcessSP ProcessFreeBSDKernel::CreateInstance(lldb::TargetSP target_sp, crash_file->GetPath().c_str(), O_RDONLY, nullptr, nullptr); if (kvm) return std::make_shared<ProcessFreeBSDKernelKVM>(target_sp, listener_sp, - kvm); + kvm, *crash_file); #endif } return nullptr; @@ -281,8 +282,9 @@ lldb::addr_t ProcessFreeBSDKernel::FindSymbol(const char *name) { ProcessFreeBSDKernelFVC::ProcessFreeBSDKernelFVC(lldb::TargetSP target_sp, ListenerSP listener_sp, - fvc_t *fvc) - : ProcessFreeBSDKernel(target_sp, listener_sp), m_fvc(fvc) {} + fvc_t *fvc, + const FileSpec &core_file) + : ProcessFreeBSDKernel(target_sp, listener_sp, crash_file), m_fvc(fvc) {} ProcessFreeBSDKernelFVC::~ProcessFreeBSDKernelFVC() { if (m_fvc) @@ -308,8 +310,9 @@ const char *ProcessFreeBSDKernelFVC::GetError() { return fvc_geterr(m_fvc); } ProcessFreeBSDKernelKVM::ProcessFreeBSDKernelKVM(lldb::TargetSP target_sp, ListenerSP listener_sp, - kvm_t *fvc) - : ProcessFreeBSDKernel(target_sp, listener_sp), m_kvm(fvc) {} + kvm_t *fvc, + const FileSpec &core_file) + : ProcessFreeBSDKernel(target_sp, listener_sp, core_file), m_kvm(fvc) {} ProcessFreeBSDKernelKVM::~ProcessFreeBSDKernelKVM() { if (m_kvm) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h index 5bd463126307..06c9d062441e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/FreeBSDKernel/ProcessFreeBSDKernel.h @@ -13,7 +13,8 @@ class ProcessFreeBSDKernel : public lldb_private::PostMortemProcess { public: - ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener); + ProcessFreeBSDKernel(lldb::TargetSP target_sp, lldb::ListenerSP listener, + const lldb_private::FileSpec &core_file); static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index f561c21b9d91..77b4301ea22e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -180,8 +180,6 @@ void NativeThreadNetBSD::SetStepping() { } std::string NativeThreadNetBSD::GetName() { - Log *log = GetLog(POSIXLog::Thread); - #ifdef PT_LWPSTATUS struct ptrace_lwpstatus info = {}; info.pl_lwpid = m_tid; @@ -193,6 +191,8 @@ std::string NativeThreadNetBSD::GetName() { return info.pl_name; #else std::vector<struct kinfo_lwp> infos; + Log *log = GetLog(POSIXLog::Thread); + int mib[5] = {CTL_KERN, KERN_LWP, static_cast<int>(m_process.GetID()), sizeof(struct kinfo_lwp), 0}; size_t size; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h index 3b0f55d35e5d..2670b34f6b0a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -20,25 +20,30 @@ public: AuxVector(const lldb_private::DataExtractor &data); /// Constants describing the type of entry. - /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX + /// On Linux and FreeBSD, running "LD_SHOW_AUXV=1 ./executable" will spew AUX /// information. Added AUXV prefix to avoid potential conflicts with system- - /// defined macros + /// defined macros. For FreeBSD, the numbers can be found in sys/elf_common.h. enum EntryType { - AUXV_AT_NULL = 0, ///< End of auxv. - AUXV_AT_IGNORE = 1, ///< Ignore entry. - AUXV_AT_EXECFD = 2, ///< File descriptor of program. - AUXV_AT_PHDR = 3, ///< Program headers. - AUXV_AT_PHENT = 4, ///< Size of program header. - AUXV_AT_PHNUM = 5, ///< Number of program headers. - AUXV_AT_PAGESZ = 6, ///< Page size. - AUXV_AT_BASE = 7, ///< Interpreter base address. - AUXV_AT_FLAGS = 8, ///< Flags. - AUXV_AT_ENTRY = 9, ///< Program entry point. - AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. - AUXV_AT_UID = 11, ///< UID. - AUXV_AT_EUID = 12, ///< Effective UID. - AUXV_AT_GID = 13, ///< GID. - AUXV_AT_EGID = 14, ///< Effective GID. + AUXV_AT_NULL = 0, ///< End of auxv. + AUXV_AT_IGNORE = 1, ///< Ignore entry. + AUXV_AT_EXECFD = 2, ///< File descriptor of program. + AUXV_AT_PHDR = 3, ///< Program headers. + AUXV_AT_PHENT = 4, ///< Size of program header. + AUXV_AT_PHNUM = 5, ///< Number of program headers. + AUXV_AT_PAGESZ = 6, ///< Page size. + AUXV_AT_BASE = 7, ///< Interpreter base address. + AUXV_AT_FLAGS = 8, ///< Flags. + AUXV_AT_ENTRY = 9, ///< Program entry point. + AUXV_AT_NOTELF = 10, ///< Set if program is not an ELF. + AUXV_AT_UID = 11, ///< UID. + AUXV_AT_EUID = 12, ///< Effective UID. + AUXV_AT_GID = 13, ///< GID. + AUXV_AT_EGID = 14, ///< Effective GID. + + // At this point Linux and FreeBSD diverge and many of the following values + // are Linux specific. If you use them make sure you are in Linux specific + // code or they have the same value on other platforms. + AUXV_AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)). AUXV_AT_PLATFORM = 15, ///< String identifying platform. AUXV_AT_HWCAP = @@ -60,6 +65,10 @@ public: AUXV_AT_L1D_CACHESHAPE = 35, AUXV_AT_L2_CACHESHAPE = 36, AUXV_AT_L3_CACHESHAPE = 37, + + // Platform specific values which may overlap the Linux values. + + AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value. }; std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp index 6bf8a0dc28b2..ef71a964eaf2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp @@ -94,6 +94,38 @@ static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { LLDB_INVALID_ADDRESS); } +static int GetSoftwareBreakpointSize(const ArchSpec &arch, + lldb::addr_t next_flags) { + if (arch.GetMachine() == llvm::Triple::arm) { + if (next_flags & 0x20) + // Thumb mode + return 2; + // Arm mode + return 4; + } + if (arch.IsMIPS() || arch.GetTriple().isPPC64() || + arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) + return 4; + return 0; +} + +static Status SetSoftwareBreakpointOnPC(const ArchSpec &arch, lldb::addr_t pc, + lldb::addr_t next_flags, + NativeProcessProtocol &process) { + int size_hint = GetSoftwareBreakpointSize(arch, next_flags); + Status error; + error = process.SetBreakpoint(pc, size_hint, /*hardware=*/false); + + // If setting the breakpoint fails because pc is out of the address + // space, ignore it and let the debugee segfault. + if (error.GetError() == EIO || error.GetError() == EFAULT) + return Status(); + if (error.Fail()) + return error; + + return Status(); +} + Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( NativeThreadProtocol &thread) { Status error; @@ -115,8 +147,23 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( emulator_up->SetWriteMemCallback(&WriteMemoryCallback); emulator_up->SetWriteRegCallback(&WriteRegisterCallback); - if (!emulator_up->ReadInstruction()) - return Status("Read instruction failed!"); + if (!emulator_up->ReadInstruction()) { + // try to get at least the size of next instruction to set breakpoint. + auto instr_size = emulator_up->GetLastInstrSize(); + if (!instr_size) + return Status("Read instruction failed!"); + bool success = false; + auto pc = emulator_up->ReadRegisterUnsigned(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC, + LLDB_INVALID_ADDRESS, &success); + if (!success) + return Status("Reading pc failed!"); + lldb::addr_t next_pc = pc + *instr_size; + auto result = + SetSoftwareBreakpointOnPC(arch, next_pc, /* next_flags */ 0x0, process); + m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); + return result; + } bool emulation_result = emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); @@ -157,29 +204,7 @@ Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( // modifying the PC but we don't know how. return Status("Instruction emulation failed unexpectedly."); } - - int size_hint = 0; - if (arch.GetMachine() == llvm::Triple::arm) { - if (next_flags & 0x20) { - // Thumb mode - size_hint = 2; - } else { - // Arm mode - size_hint = 4; - } - } else if (arch.IsMIPS() || arch.GetTriple().isPPC64() || - arch.GetTriple().isRISCV() || arch.GetTriple().isLoongArch()) - size_hint = 4; - error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false); - - // If setting the breakpoint fails because next_pc is out of the address - // space, ignore it and let the debugee segfault. - if (error.GetError() == EIO || error.GetError() == EFAULT) { - return Status(); - } else if (error.Fail()) - return error; - + auto result = SetSoftwareBreakpointOnPC(arch, next_pc, next_flags, process); m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); - - return Status(); + return result; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp index 1834a94dc026..035ce00e1162 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_riscv64.cpp @@ -58,7 +58,7 @@ RegisterContextPOSIX_riscv64::GetRegisterInfoAtIndex(size_t reg) { } size_t RegisterContextPOSIX_riscv64::GetRegisterSetCount() { - return m_register_info_up->GetRegisterCount(); + return m_register_info_up->GetRegisterSetCount(); } const lldb_private::RegisterSet * diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp index 51553817921f..7c8dba368093 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp @@ -1,4 +1,4 @@ -//===-- RegisterFlagsLinux_arm64.cpp --------------------------------------===// +//===-- RegisterFlagsDetector_arm64.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,11 +6,12 @@ // //===----------------------------------------------------------------------===// -#include "RegisterFlagsLinux_arm64.h" +#include "RegisterFlagsDetector_arm64.h" #include "lldb/lldb-private-types.h" // This file is built on all systems because it is used by native processes and // core files, so we manually define the needed HWCAP values here. +// These values are the same for Linux and FreeBSD. #define HWCAP_FPHP (1ULL << 9) #define HWCAP_ASIMDHP (1ULL << 10) @@ -20,14 +21,18 @@ #define HWCAP2_BTI (1ULL << 17) #define HWCAP2_MTE (1ULL << 18) #define HWCAP2_AFP (1ULL << 20) +#define HWCAP2_SME (1ULL << 23) #define HWCAP2_EBF16 (1ULL << 32) using namespace lldb_private; -LinuxArm64RegisterFlags::Fields -LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::Fields +Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { (void)hwcap; - (void)hwcap2; + + if (!(hwcap2 & HWCAP2_SME)) + return {}; + // Represents the pseudo register that lldb-server builds, which itself // matches the architectural register SCVR. The fields match SVCR in the Arm // manual. @@ -37,23 +42,33 @@ LinuxArm64RegisterFlags::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { }; } -LinuxArm64RegisterFlags::Fields -LinuxArm64RegisterFlags::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::Fields +Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, + uint64_t hwcap2) { (void)hwcap; - (void)hwcap2; + + if (!(hwcap2 & HWCAP2_MTE)) + return {}; + // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines // used to build the value. + + static const FieldEnum tcf_enum( + "tcf_enum", + {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}}); return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT. - {"TCF_ASYNC", 2}, - {"TCF_SYNC", 1}, + {"TCF", 1, 2, &tcf_enum}, {"TAGGED_ADDR_ENABLE", 0}}; } -LinuxArm64RegisterFlags::Fields -LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::Fields +Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { + static const FieldEnum rmode_enum( + "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}}); + std::vector<RegisterFlags::Field> fpcr_fields{ - {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23}, + {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum}, // Bits 21-20 are "Stride" which is unused in AArch64 state. }; @@ -86,8 +101,8 @@ LinuxArm64RegisterFlags::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { return fpcr_fields; } -LinuxArm64RegisterFlags::Fields -LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::Fields +Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { // fpsr's contents are constant. (void)hwcap; (void)hwcap2; @@ -106,8 +121,8 @@ LinuxArm64RegisterFlags::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { }; } -LinuxArm64RegisterFlags::Fields -LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::Fields +Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { // The fields here are a combination of the Arm manual's SPSR_EL1, // plus a few changes where Linux has decided not to make use of them at all, // or at least not from userspace. @@ -124,7 +139,7 @@ LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { cpsr_fields.push_back({"DIT", 24}); // UAO and PAN are bits 23 and 22 and have no meaning for userspace so - // are treated as reserved by the kernel. + // are treated as reserved by the kernels. cpsr_fields.push_back({"SS", 21}); cpsr_fields.push_back({"IL", 20}); @@ -152,14 +167,14 @@ LinuxArm64RegisterFlags::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { return cpsr_fields; } -void LinuxArm64RegisterFlags::DetectFields(uint64_t hwcap, uint64_t hwcap2) { +void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2) { for (auto ® : m_registers) reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2)); m_has_detected = true; } -void LinuxArm64RegisterFlags::UpdateRegisterInfo(const RegisterInfo *reg_info, - uint32_t num_regs) { +void Arm64RegisterFlagsDetector::UpdateRegisterInfo( + const RegisterInfo *reg_info, uint32_t num_regs) { assert(m_has_detected && "Must call DetectFields before updating register info."); @@ -199,4 +214,4 @@ void LinuxArm64RegisterFlags::UpdateRegisterInfo(const RegisterInfo *reg_info, // We do not assert that search_registers is empty here, because it may // contain registers from optional extensions that are not present on the // current target. -}
\ No newline at end of file +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h index 660bef08700f..a5bb38670b9c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h @@ -1,4 +1,4 @@ -//===-- RegisterFlagsLinux_arm64.h ------------------------------*- C++ -*-===// +//===-- RegisterFlagsDetector_arm64.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. @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H -#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H #include "lldb/Target/RegisterFlags.h" #include "llvm/ADT/StringRef.h" @@ -17,12 +17,12 @@ namespace lldb_private { struct RegisterInfo; -/// This class manages the storage and detection of register field information -/// for Arm64 Linux registers. The same register may have different fields on -/// different CPUs. This class abstracts out the field detection process so we -/// can use it on live processes and core files. +/// This class manages the storage and detection of register field information. +/// The same register may have different fields on different CPUs. This class +/// abstracts out the field detection process so we can use it on live processes +/// and core files. /// -/// The general way to use this class is: +/// The way to use this class is: /// * Make an instance somewhere that will last as long as the debug session /// (because your final register info will point to this instance). /// * Read hardware capabilities from a core note, binary, prctl, etc. @@ -33,13 +33,13 @@ struct RegisterInfo; /// This must be done in that order, and you should ensure that if multiple /// threads will reference the information, a mutex is used to make sure only /// one calls DetectFields. -class LinuxArm64RegisterFlags { +class Arm64RegisterFlagsDetector { public: /// For the registers listed in this class, detect which fields are /// present. Must be called before UpdateRegisterInfos. /// If called more than once, fields will be redetected each time from - /// scratch. If you do not have access to hwcap, just pass 0 for each one, you - /// will only get unconditional fields. + /// scratch. If the target would not have this register at all, the list of + /// fields will be left empty. void DetectFields(uint64_t hwcap, uint64_t hwcap2); /// Add the field information of any registers named in this class, @@ -63,7 +63,7 @@ private: struct RegisterEntry { RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector) - : m_name(name), m_flags(std::string(name) + "_flags", size, {{"", 0}}), + : m_name(name), m_flags(std::string(name) + "_flags", size, {}), m_detector(detector) {} llvm::StringRef m_name; @@ -83,4 +83,4 @@ private: } // namespace lldb_private -#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSLINUX_ARM64_H
\ No newline at end of file +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERFLAGSDETECTOR_ARM64_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 565941d3168f..25cee369d7ee 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -26,6 +26,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include <optional> @@ -90,9 +92,7 @@ bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) { Target &target = *exe_ctx.GetTargetPtr(); Process &process = *exe_ctx.GetProcessPtr(); - ABISP abi_sp = process.GetABI(); const ArchSpec &arch = target.GetArchitecture(); - assert(abi_sp && "Missing ABI info"); // Check for a ptrauth-enabled target. const bool ptrauth_enabled_target = @@ -108,6 +108,9 @@ bool StopInfoMachException::DeterminePtrauthFailure(ExecutionContext &exe_ctx) { strm.Printf("Note: Possible pointer authentication failure detected.\n"); }; + ABISP abi_sp = process.GetABI(); + assert(abi_sp && "Missing ABI info"); + // Check if we have a "brk 0xc47x" trap, where the value that failed to // authenticate is in x16. Address current_address = current_frame->GetFrameCodeAddress(); @@ -491,14 +494,13 @@ static StopInfoSP GetStopInfoForHardwareBP(Thread &thread, Target *target, uint64_t exc_sub_sub_code) { // Try hardware watchpoint. if (target) { - // LWP_TODO: We need to find the WatchpointResource that matches - // the address, and evaluate its Watchpoints. - // The exc_sub_code indicates the data break address. - lldb::WatchpointSP wp_sp = - target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code); - if (wp_sp && wp_sp->IsEnabled()) { - return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID()); + WatchpointResourceSP wp_rsrc_sp = + target->GetProcessSP()->GetWatchpointResourceList().FindByAddress( + (addr_t)exc_sub_code); + if (wp_rsrc_sp && wp_rsrc_sp->GetNumberOfConstituents() > 0) { + return StopInfo::CreateStopReasonWithWatchpointID( + thread, wp_rsrc_sp->GetConstituentAtIndex(0)->GetID()); } } @@ -597,6 +599,7 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( if (exc_type == 0) return StopInfoSP(); + bool not_stepping_but_got_singlestep_exception = false; uint32_t pc_decrement = 0; ExecutionContext exe_ctx(thread.shared_from_this()); Target *target = exe_ctx.GetTargetPtr(); @@ -721,30 +724,8 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( // is set is_actual_breakpoint = true; is_trace_if_actual_breakpoint_missing = true; -#ifndef NDEBUG - if (thread.GetTemporaryResumeState() != eStateStepping) { - StreamString s; - s.Printf("CreateStopReasonWithMachException got EXC_BREAKPOINT [1,0] " - "indicating trace event, but thread is not tracing, it has " - "ResumeState %d", - thread.GetTemporaryResumeState()); - if (RegisterContextSP regctx = thread.GetRegisterContext()) { - if (const RegisterInfo *ri = regctx->GetRegisterInfoByName("esr")) { - uint32_t esr = - (uint32_t)regctx->ReadRegisterAsUnsigned(ri, UINT32_MAX); - if (esr != UINT32_MAX) { - s.Printf(" esr value: 0x%" PRIx32, esr); - } - } - } - thread.GetProcess()->DumpPluginHistory(s); - llvm::report_fatal_error(s.GetData()); - lldbassert( - false && - "CreateStopReasonWithMachException got EXC_BREAKPOINT [1,0] " - "indicating trace event, but thread was not doing a step."); - } -#endif + if (thread.GetTemporaryResumeState() != eStateStepping) + not_stepping_but_got_singlestep_exception = true; } if (exc_code == 0x102) // EXC_ARM_DA_DEBUG { @@ -826,6 +807,56 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( break; } - return StopInfoSP(new StopInfoMachException(thread, exc_type, exc_data_count, - exc_code, exc_sub_code)); + return std::make_shared<StopInfoMachException>( + thread, exc_type, exc_data_count, exc_code, exc_sub_code, + not_stepping_but_got_singlestep_exception); +} + +// Detect an unusual situation on Darwin where: +// +// 0. We did an instruction-step before this. +// 1. We have a hardware breakpoint or watchpoint set. +// 2. We resumed the process, but not with an instruction-step. +// 3. The thread gets an "instruction-step completed" mach exception. +// 4. The pc has not advanced - it is the same as before. +// +// This method returns true for that combination of events. +bool StopInfoMachException::WasContinueInterrupted(Thread &thread) { + Log *log = GetLog(LLDBLog::Step); + + // We got an instruction-step completed mach exception but we were not + // doing an instruction step on this thread. + if (!m_not_stepping_but_got_singlestep_exception) + return false; + + RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); + std::optional<addr_t> prev_pc = thread.GetPreviousFrameZeroPC(); + if (!reg_ctx_sp || !prev_pc) + return false; + + // The previous pc value and current pc value are the same. + if (*prev_pc != reg_ctx_sp->GetPC()) + return false; + + // We have a watchpoint -- this is the kernel bug. + ProcessSP process_sp = thread.GetProcess(); + if (process_sp->GetWatchpointResourceList().GetSize()) { + LLDB_LOGF(log, + "Thread stopped with insn-step completed mach exception but " + "thread was not stepping; there is a hardware watchpoint set."); + return true; + } + + // We have a hardware breakpoint -- this is the kernel bug. + auto &bp_site_list = process_sp->GetBreakpointSiteList(); + for (auto &site : bp_site_list.Sites()) { + if (site->IsHardware() && site->IsEnabled()) { + LLDB_LOGF(log, + "Thread stopped with insn-step completed mach exception but " + "thread was not stepping; there is a hardware breakpoint set."); + return true; + } + } + + return false; } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h index 541ef5e69565..c612ac400b4c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/Utility/StopInfoMachException.h @@ -31,9 +31,12 @@ public: // Constructors and Destructors StopInfoMachException(Thread &thread, uint32_t exc_type, uint32_t exc_data_count, uint64_t exc_code, - uint64_t exc_subcode) + uint64_t exc_subcode, + bool not_stepping_but_got_singlestep_exception) : StopInfo(thread, exc_type), m_exc_data_count(exc_data_count), - m_exc_code(exc_code), m_exc_subcode(exc_subcode) {} + m_exc_code(exc_code), m_exc_subcode(exc_subcode), + m_not_stepping_but_got_singlestep_exception( + not_stepping_but_got_singlestep_exception) {} ~StopInfoMachException() override = default; @@ -58,10 +61,14 @@ public: uint64_t exc_code, uint64_t exc_sub_code, uint64_t exc_sub_sub_code, bool pc_already_adjusted = true, bool adjust_pc_if_needed = false); + bool WasContinueInterrupted(Thread &thread) override; + protected: uint32_t m_exc_data_count; uint64_t m_exc_code; uint64_t m_exc_subcode; + + bool m_not_stepping_but_got_singlestep_exception; }; } // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index 7723009787f7..30af9345999c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/contrib/llvm-project/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), m_core_file(core_file) {} + : PostMortemProcess(target_sp, listener_sp, core_file) {} // Destructor ProcessElfCore::~ProcessElfCore() { @@ -250,6 +250,9 @@ Status ProcessElfCore::DoLoadCore() { } } + // Try to find gnu build id before we load the executable. + UpdateBuildIdForNTFileEntries(); + // Core files are useless without the main executable. See if we can locate // the main executable using data we found in the core file notes. lldb::ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); @@ -258,11 +261,12 @@ Status ProcessElfCore::DoLoadCore() { if (!m_nt_file_entries.empty()) { 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, FileSpec::Style::native); if (exe_module_spec.GetFileSpec()) { - exe_module_sp = GetTarget().GetOrCreateModule(exe_module_spec, - true /* notify */); + exe_module_sp = + GetTarget().GetOrCreateModule(exe_module_spec, true /* notify */); if (exe_module_sp) GetTarget().SetExecutableModule(exe_module_sp, eLoadDependentsNo); } @@ -271,6 +275,12 @@ Status ProcessElfCore::DoLoadCore() { return error; } +void ProcessElfCore::UpdateBuildIdForNTFileEntries() { + for (NT_FILE_Entry &entry : m_nt_file_entries) { + entry.uuid = FindBuidIdInCoreMemory(entry.start); + } +} + lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { if (m_dyld_up.get() == nullptr) m_dyld_up.reset(DynamicLoader::FindPlugin( @@ -983,6 +993,67 @@ llvm::Error ProcessElfCore::ParseThreadContextsFromNoteSegment( } } +UUID ProcessElfCore::FindBuidIdInCoreMemory(lldb::addr_t address) { + UUID invalid_uuid; + const uint32_t addr_size = GetAddressByteSize(); + const size_t elf_header_size = addr_size == 4 ? sizeof(llvm::ELF::Elf32_Ehdr) + : sizeof(llvm::ELF::Elf64_Ehdr); + + std::vector<uint8_t> elf_header_bytes; + elf_header_bytes.resize(elf_header_size); + Status error; + size_t byte_read = + ReadMemory(address, elf_header_bytes.data(), elf_header_size, error); + if (byte_read != elf_header_size || + !elf::ELFHeader::MagicBytesMatch(elf_header_bytes.data())) + return invalid_uuid; + DataExtractor elf_header_data(elf_header_bytes.data(), elf_header_size, + GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + + elf::ELFHeader elf_header; + elf_header.Parse(elf_header_data, &offset); + + const lldb::addr_t ph_addr = address + elf_header.e_phoff; + + std::vector<uint8_t> ph_bytes; + ph_bytes.resize(elf_header.e_phentsize); + for (unsigned int i = 0; i < elf_header.e_phnum; ++i) { + byte_read = ReadMemory(ph_addr + i * elf_header.e_phentsize, + ph_bytes.data(), elf_header.e_phentsize, error); + if (byte_read != elf_header.e_phentsize) + break; + DataExtractor program_header_data(ph_bytes.data(), elf_header.e_phentsize, + GetByteOrder(), addr_size); + offset = 0; + elf::ELFProgramHeader program_header; + program_header.Parse(program_header_data, &offset); + if (program_header.p_type != llvm::ELF::PT_NOTE) + continue; + + std::vector<uint8_t> note_bytes; + note_bytes.resize(program_header.p_memsz); + + byte_read = ReadMemory(program_header.p_vaddr, note_bytes.data(), + program_header.p_memsz, error); + if (byte_read != program_header.p_memsz) + continue; + DataExtractor segment_data(note_bytes.data(), note_bytes.size(), + GetByteOrder(), addr_size); + auto notes_or_error = parseSegment(segment_data); + if (!notes_or_error) + return invalid_uuid; + for (const CoreNote ¬e : *notes_or_error) { + if (note.info.n_namesz == 4 && + note.info.n_type == llvm::ELF::NT_GNU_BUILD_ID && + "GNU" == note.info.n_name && + note.data.ValidOffsetForDataOfSize(0, note.info.n_descsz)) + return UUID(note.data.GetData().take_front(note.info.n_descsz)); + } + } + return invalid_uuid; +} + uint32_t ProcessElfCore::GetNumThreadContexts() { if (!m_thread_data_valid) DoLoadCore(); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 1454e8735a67..668a7c484674 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -117,6 +117,10 @@ 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 @@ -127,7 +131,6 @@ private: VMRangeToPermissions; lldb::ModuleSP m_core_module_sp; - lldb_private::FileSpec m_core_file; std::string m_dyld_plugin_name; // True if m_thread_contexts contains valid entries @@ -159,6 +162,12 @@ private: // Returns number of thread contexts stored in the core file uint32_t GetNumThreadContexts(); + // Populate gnu uuid for each NT_FILE entry + void UpdateBuildIdForNTFileEntries(); + + // Returns the value of certain type of note of a given start address + lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address); + // Parse a contiguous address range of the process from LOAD segment lldb::addr_t AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 07501c10ec3c..413bf1bbdb2a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -10,7 +10,7 @@ #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "Plugins/Process/Utility/AuxVector.h" -#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h" +#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h" #include "Plugins/Process/elf-core/ProcessElfCore.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" @@ -79,17 +79,19 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( ProcessElfCore *process = static_cast<ProcessElfCore *>(thread.GetProcess().get()); - if (process->GetArchitecture().GetTriple().getOS() == llvm::Triple::Linux) { + llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS(); + if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) { AuxVector aux_vec(process->GetAuxvData()); - std::optional<uint64_t> auxv_at_hwcap = - aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP); + std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue( + os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP + : AuxVector::AUXV_AT_HWCAP); std::optional<uint64_t> auxv_at_hwcap2 = aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); - m_linux_register_flags.DetectFields(auxv_at_hwcap.value_or(0), - auxv_at_hwcap2.value_or(0)); - m_linux_register_flags.UpdateRegisterInfo(GetRegisterInfo(), - GetRegisterCount()); + m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0), + auxv_at_hwcap2.value_or(0)); + m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(), + GetRegisterCount()); } m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index 38e958851dfe..ff94845e58d6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -11,7 +11,7 @@ #include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" -#include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h" +#include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Utility/DataBufferHeap.h" @@ -75,7 +75,7 @@ private: struct sme_pseudo_regs m_sme_pseudo_regs; - lldb_private::LinuxArm64RegisterFlags m_linux_register_flags; + lldb_private::Arm64RegisterFlagsDetector m_register_flags_detector; const uint8_t *GetSVEBuffer(uint64_t offset = 0); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp new file mode 100644 index 000000000000..5ba18cdb9889 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.cpp @@ -0,0 +1,82 @@ +//===-- RegisterContextPOSIXCore_riscv64.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 "RegisterContextPOSIXCore_riscv64.h" + +#include "lldb/Utility/DataBufferHeap.h" + +using namespace lldb_private; + +std::unique_ptr<RegisterContextCorePOSIX_riscv64> +RegisterContextCorePOSIX_riscv64::Create(Thread &thread, const ArchSpec &arch, + const DataExtractor &gpregset, + llvm::ArrayRef<CoreNote> notes) { + return std::unique_ptr<RegisterContextCorePOSIX_riscv64>( + new RegisterContextCorePOSIX_riscv64( + thread, std::make_unique<RegisterInfoPOSIX_riscv64>(arch, Flags()), + gpregset, notes)); +} + +RegisterContextCorePOSIX_riscv64::RegisterContextCorePOSIX_riscv64( + Thread &thread, std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info, + const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) + : RegisterContextPOSIX_riscv64(thread, std::move(register_info)) { + + m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), + gpregset.GetByteSize()); + m_gpr.SetData(m_gpr_buffer); + m_gpr.SetByteOrder(gpregset.GetByteOrder()); + + ArchSpec arch = m_register_info_up->GetTargetArchitecture(); + DataExtractor fpregset = getRegset(notes, arch.GetTriple(), FPR_Desc); + m_fpr_buffer = std::make_shared<DataBufferHeap>(fpregset.GetDataStart(), + fpregset.GetByteSize()); + m_fpr.SetData(m_fpr_buffer); + m_fpr.SetByteOrder(fpregset.GetByteOrder()); +} + +RegisterContextCorePOSIX_riscv64::~RegisterContextCorePOSIX_riscv64() = default; + +bool RegisterContextCorePOSIX_riscv64::ReadGPR() { return true; } + +bool RegisterContextCorePOSIX_riscv64::ReadFPR() { return true; } + +bool RegisterContextCorePOSIX_riscv64::WriteGPR() { + assert(false && "Writing registers is not allowed for core dumps"); + return false; +} + +bool RegisterContextCorePOSIX_riscv64::WriteFPR() { + assert(false && "Writing registers is not allowed for core dumps"); + return false; +} + +bool RegisterContextCorePOSIX_riscv64::ReadRegister( + const RegisterInfo *reg_info, RegisterValue &value) { + const uint8_t *src = nullptr; + lldb::offset_t offset = reg_info->byte_offset; + + if (IsGPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + src = m_gpr.GetDataStart(); + } else if (IsFPR(reg_info->kinds[lldb::eRegisterKindLLDB])) { + src = m_fpr.GetDataStart(); + offset -= GetGPRSize(); + } else { + return false; + } + + Status error; + value.SetFromMemoryData(*reg_info, src + offset, reg_info->byte_size, + lldb::eByteOrderLittle, error); + return error.Success(); +} + +bool RegisterContextCorePOSIX_riscv64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue &value) { + return false; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h new file mode 100644 index 000000000000..3cf9531df2c1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_riscv64.h @@ -0,0 +1,60 @@ +//===-- RegisterContextPOSIXCore_riscv64.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_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H +#define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H + +#include "Plugins/Process/Utility/RegisterContextPOSIX_riscv64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_riscv64.h" + +#include "Plugins/Process/elf-core/RegisterUtilities.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" + +#include <memory> + +class RegisterContextCorePOSIX_riscv64 : public RegisterContextPOSIX_riscv64 { +public: + static std::unique_ptr<RegisterContextCorePOSIX_riscv64> + Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef<lldb_private::CoreNote> notes); + + ~RegisterContextCorePOSIX_riscv64() override; + + bool ReadRegister(const lldb_private::RegisterInfo *reg_info, + lldb_private::RegisterValue &value) override; + + bool WriteRegister(const lldb_private::RegisterInfo *reg_info, + const lldb_private::RegisterValue &value) override; + +protected: + RegisterContextCorePOSIX_riscv64( + lldb_private::Thread &thread, + std::unique_ptr<RegisterInfoPOSIX_riscv64> register_info, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef<lldb_private::CoreNote> notes); + + bool ReadGPR() override; + + bool ReadFPR() override; + + bool WriteGPR() override; + + bool WriteFPR() override; + +private: + lldb::DataBufferSP m_gpr_buffer; + lldb::DataBufferSP m_fpr_buffer; + + lldb_private::DataExtractor m_gpr; + lldb_private::DataExtractor m_fpr; +}; + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_RISCV64_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index a7c620c883ba..c931583cf21c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -37,6 +37,7 @@ #include "RegisterContextPOSIXCore_mips64.h" #include "RegisterContextPOSIXCore_powerpc.h" #include "RegisterContextPOSIXCore_ppc64le.h" +#include "RegisterContextPOSIXCore_riscv64.h" #ifdef LLDB_ENABLE_ALL #include "RegisterContextPOSIXCore_s390x.h" #endif // LLDB_ENABLE_ALL @@ -174,7 +175,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { } if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 && - arch.GetMachine() != llvm::Triple::arm) { + arch.GetMachine() != llvm::Triple::arm && + arch.GetMachine() != llvm::Triple::riscv64) { LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported", __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); assert(false && "Architecture or OS not supported"); @@ -190,6 +192,10 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { *this, std::make_unique<RegisterInfoPOSIX_arm>(arch), m_gpregset_data, m_notes); break; + case llvm::Triple::riscv64: + m_thread_reg_ctx_sp = RegisterContextCorePOSIX_riscv64::Create( + *this, arch, m_gpregset_data, m_notes); + break; case llvm::Triple::mipsel: case llvm::Triple::mips: m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_mips64>( diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 8a47eed3d7cb..187370eb36ca 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -539,9 +539,8 @@ bool GDBRemoteCommunication::DecompressPacket() { else if (m_compression_type == CompressionType::ZlibDeflate) scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_ZLIB); else if (m_compression_type == CompressionType::LZMA) - scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZMA); - else if (m_compression_type == CompressionType::LZFSE) - scratchbuf_size = compression_decode_scratch_buffer_size (COMPRESSION_LZFSE); + scratchbuf_size = + compression_decode_scratch_buffer_size(COMPRESSION_LZMA); if (scratchbuf_size > 0) { m_decompression_scratch = (void*) malloc (scratchbuf_size); m_decompression_scratch_type = m_compression_type; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 7bb449841851..74e392249a94 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/MemoryRegionInfo.h" @@ -403,6 +404,18 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { x.split(compressions, ','); if (!compressions.empty()) MaybeEnableCompression(compressions); + } else if (x.consume_front("SupportedWatchpointTypes=")) { + llvm::SmallVector<llvm::StringRef, 4> watchpoint_types; + x.split(watchpoint_types, ','); + m_watchpoint_types = eWatchpointHardwareFeatureUnknown; + for (auto wp_type : watchpoint_types) { + if (wp_type == "x86_64") + m_watchpoint_types |= eWatchpointHardwareX86; + if (wp_type == "aarch64-mask") + m_watchpoint_types |= eWatchpointHardwareArmMASK; + if (wp_type == "aarch64-bas") + m_watchpoint_types |= eWatchpointHardwareArmBAS; + } } else if (x.consume_front("PacketSize=")) { StringExtractorGDBRemote packet_response(x); m_max_packet_size = @@ -1039,10 +1052,10 @@ bool GDBRemoteCommunicationClient::GetGDBServerVersion() { llvm::StringRef name, value; bool success = false; while (response.GetNameColonValue(name, value)) { - if (name.equals("name")) { + if (name == "name") { success = true; m_gdb_server_name = std::string(value); - } else if (name.equals("version")) { + } else if (name == "version") { llvm::StringRef major, minor; std::tie(major, minor) = value.split('.'); if (!major.getAsInteger(0, m_gdb_server_version)) @@ -1179,12 +1192,12 @@ bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { static void ParseOSType(llvm::StringRef value, std::string &os_name, std::string &environment) { - if (value.equals("iossimulator") || value.equals("tvossimulator") || - value.equals("watchossimulator") || value.equals("xrossimulator") || - value.equals("visionossimulator")) { + if (value == "iossimulator" || value == "tvossimulator" || + value == "watchossimulator" || value == "xrossimulator" || + value == "visionossimulator") { environment = "simulator"; os_name = value.drop_back(environment.size()).str(); - } else if (value.equals("maccatalyst")) { + } else if (value == "maccatalyst") { os_name = "ios"; environment = "macabi"; } else { @@ -1217,44 +1230,44 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { ByteOrder byte_order = eByteOrderInvalid; uint32_t num_keys_decoded = 0; while (response.GetNameColonValue(name, value)) { - if (name.equals("cputype")) { + if (name == "cputype") { // exception type in big endian hex if (!value.getAsInteger(0, cpu)) ++num_keys_decoded; - } else if (name.equals("cpusubtype")) { + } else if (name == "cpusubtype") { // exception count in big endian hex if (!value.getAsInteger(0, sub)) ++num_keys_decoded; - } else if (name.equals("arch")) { + } else if (name == "arch") { arch_name = std::string(value); ++num_keys_decoded; - } else if (name.equals("triple")) { + } else if (name == "triple") { StringExtractor extractor(value); extractor.GetHexByteString(triple); ++num_keys_decoded; - } else if (name.equals("distribution_id")) { + } else if (name == "distribution_id") { StringExtractor extractor(value); extractor.GetHexByteString(m_host_distribution_id); ++num_keys_decoded; - } else if (name.equals("os_build")) { + } else if (name == "os_build") { StringExtractor extractor(value); extractor.GetHexByteString(m_os_build); ++num_keys_decoded; - } else if (name.equals("hostname")) { + } else if (name == "hostname") { StringExtractor extractor(value); extractor.GetHexByteString(m_hostname); ++num_keys_decoded; - } else if (name.equals("os_kernel")) { + } else if (name == "os_kernel") { StringExtractor extractor(value); extractor.GetHexByteString(m_os_kernel); ++num_keys_decoded; - } else if (name.equals("ostype")) { + } else if (name == "ostype") { ParseOSType(value, os_name, environment); ++num_keys_decoded; - } else if (name.equals("vendor")) { + } else if (name == "vendor") { vendor_name = std::string(value); ++num_keys_decoded; - } else if (name.equals("endian")) { + } else if (name == "endian") { byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) .Case("little", eByteOrderLittle) .Case("big", eByteOrderBig) @@ -1262,30 +1275,30 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { .Default(eByteOrderInvalid); if (byte_order != eByteOrderInvalid) ++num_keys_decoded; - } else if (name.equals("ptrsize")) { + } else if (name == "ptrsize") { if (!value.getAsInteger(0, pointer_byte_size)) ++num_keys_decoded; - } else if (name.equals("addressing_bits")) { + } else if (name == "addressing_bits") { if (!value.getAsInteger(0, m_low_mem_addressing_bits)) { ++num_keys_decoded; } - } else if (name.equals("high_mem_addressing_bits")) { + } else if (name == "high_mem_addressing_bits") { if (!value.getAsInteger(0, m_high_mem_addressing_bits)) ++num_keys_decoded; - } else if (name.equals("low_mem_addressing_bits")) { + } else if (name == "low_mem_addressing_bits") { if (!value.getAsInteger(0, m_low_mem_addressing_bits)) ++num_keys_decoded; - } else if (name.equals("os_version") || - name.equals("version")) // Older debugserver binaries used - // the "version" key instead of - // "os_version"... + } else if (name == "os_version" || + name == "version") // Older debugserver binaries used + // the "version" key instead of + // "os_version"... { if (!m_os_version.tryParse(value)) ++num_keys_decoded; - } else if (name.equals("maccatalyst_version")) { + } else if (name == "maccatalyst_version") { if (!m_maccatalyst_version.tryParse(value)) ++num_keys_decoded; - } else if (name.equals("watchpoint_exceptions_received")) { + } else if (name == "watchpoint_exceptions_received") { m_watchpoints_trigger_after_instruction = llvm::StringSwitch<LazyBool>(value) .Case("before", eLazyBoolNo) @@ -1293,14 +1306,14 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { .Default(eLazyBoolCalculate); if (m_watchpoints_trigger_after_instruction != eLazyBoolCalculate) ++num_keys_decoded; - } else if (name.equals("default_packet_timeout")) { + } else if (name == "default_packet_timeout") { uint32_t timeout_seconds; if (!value.getAsInteger(0, timeout_seconds)) { m_default_packet_timeout = seconds(timeout_seconds); SetPacketTimeout(m_default_packet_timeout); ++num_keys_decoded; } - } else if (name.equals("vm-page-size")) { + } else if (name == "vm-page-size") { int page_size; if (!value.getAsInteger(0, page_size)) { m_target_vm_page_size = page_size; @@ -1555,10 +1568,10 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( bool success = true; bool saw_permissions = false; while (success && response.GetNameColonValue(name, value)) { - if (name.equals("start")) { + if (name == "start") { if (!value.getAsInteger(16, addr_value)) region_info.GetRange().SetRangeBase(addr_value); - } else if (name.equals("size")) { + } else if (name == "size") { if (!value.getAsInteger(16, addr_value)) { region_info.GetRange().SetByteSize(addr_value); if (region_info.GetRange().GetRangeEnd() < @@ -1567,8 +1580,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( region_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); } } - } else if (name.equals("permissions") && - region_info.GetRange().IsValid()) { + } else if (name == "permissions" && region_info.GetRange().IsValid()) { saw_permissions = true; if (region_info.GetRange().Contains(addr)) { if (value.contains('r')) @@ -1595,12 +1607,12 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( region_info.SetExecutable(MemoryRegionInfo::eNo); region_info.SetMapped(MemoryRegionInfo::eNo); } - } else if (name.equals("name")) { + } else if (name == "name") { StringExtractorGDBRemote name_extractor(value); std::string name; name_extractor.GetHexByteString(name); region_info.SetName(name.c_str()); - } else if (name.equals("flags")) { + } else if (name == "flags") { region_info.SetMemoryTagged(MemoryRegionInfo::eNo); llvm::StringRef flags = value; @@ -1616,7 +1628,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( } } } - } else if (name.equals("type")) { + } else if (name == "type") { std::string comma_sep_str = value.str(); size_t comma_pos; while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) { @@ -1629,13 +1641,13 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( if (comma_sep_str == "stack") { region_info.SetIsStackMemory(MemoryRegionInfo::eYes); } - } else if (name.equals("error")) { + } else if (name == "error") { StringExtractorGDBRemote error_extractor(value); std::string error_string; // Now convert the HEX bytes into a string value error_extractor.GetHexByteString(error_string); error.SetErrorString(error_string.c_str()); - } else if (name.equals("dirty-pages")) { + } else if (name == "dirty-pages") { std::vector<addr_t> dirty_page_list; for (llvm::StringRef x : llvm::split(value, ',')) { addr_t page; @@ -1812,7 +1824,7 @@ std::optional<uint32_t> GDBRemoteCommunicationClient::GetWatchpointSlotCount() { llvm::StringRef name; llvm::StringRef value; while (response.GetNameColonValue(name, value)) { - if (name.equals("num")) { + if (name == "num") { value.getAsInteger(0, m_num_supported_hardware_watchpoints); num = m_num_supported_hardware_watchpoints; } @@ -1828,6 +1840,11 @@ std::optional<uint32_t> GDBRemoteCommunicationClient::GetWatchpointSlotCount() { return num; } +WatchpointHardwareFeature +GDBRemoteCommunicationClient::GetSupportedWatchpointTypes() { + return m_watchpoint_types; +} + std::optional<bool> GDBRemoteCommunicationClient::GetWatchpointReportedAfter() { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); @@ -1988,43 +2005,43 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( std::string os_type; while (response.GetNameColonValue(name, value)) { - if (name.equals("pid")) { + if (name == "pid") { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; value.getAsInteger(0, pid); process_info.SetProcessID(pid); - } else if (name.equals("ppid")) { + } else if (name == "ppid") { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; value.getAsInteger(0, pid); process_info.SetParentProcessID(pid); - } else if (name.equals("uid")) { + } else if (name == "uid") { uint32_t uid = UINT32_MAX; value.getAsInteger(0, uid); process_info.SetUserID(uid); - } else if (name.equals("euid")) { + } else if (name == "euid") { uint32_t uid = UINT32_MAX; value.getAsInteger(0, uid); process_info.SetEffectiveUserID(uid); - } else if (name.equals("gid")) { + } else if (name == "gid") { uint32_t gid = UINT32_MAX; value.getAsInteger(0, gid); process_info.SetGroupID(gid); - } else if (name.equals("egid")) { + } else if (name == "egid") { uint32_t gid = UINT32_MAX; value.getAsInteger(0, gid); process_info.SetEffectiveGroupID(gid); - } else if (name.equals("triple")) { + } else if (name == "triple") { StringExtractor extractor(value); std::string triple; extractor.GetHexByteString(triple); process_info.GetArchitecture().SetTriple(triple.c_str()); - } else if (name.equals("name")) { + } else if (name == "name") { StringExtractor extractor(value); // The process name from ASCII hex bytes since we can't control the // characters in a process name std::string name; extractor.GetHexByteString(name); process_info.GetExecutableFile().SetFile(name, FileSpec::Style::native); - } else if (name.equals("args")) { + } else if (name == "args") { llvm::StringRef encoded_args(value), hex_arg; bool is_arg0 = true; @@ -2044,13 +2061,13 @@ bool GDBRemoteCommunicationClient::DecodeProcessInfoResponse( process_info.GetArguments().AppendArgument(arg); is_arg0 = false; } - } else if (name.equals("cputype")) { + } else if (name == "cputype") { value.getAsInteger(0, cpu); - } else if (name.equals("cpusubtype")) { + } else if (name == "cpusubtype") { value.getAsInteger(0, sub); - } else if (name.equals("vendor")) { + } else if (name == "vendor") { vendor = std::string(value); - } else if (name.equals("ostype")) { + } else if (name == "ostype") { os_type = std::string(value); } } @@ -2126,23 +2143,35 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { uint32_t num_keys_decoded = 0; lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; while (response.GetNameColonValue(name, value)) { - if (name.equals("cputype")) { + if (name == "cputype") { if (!value.getAsInteger(16, cpu)) ++num_keys_decoded; - } else if (name.equals("cpusubtype")) { - if (!value.getAsInteger(16, sub)) + } else if (name == "cpusubtype") { + if (!value.getAsInteger(16, sub)) { ++num_keys_decoded; - } else if (name.equals("triple")) { + // Workaround for pre-2024 Apple debugserver, which always + // returns arm64e on arm64e-capable hardware regardless of + // what the process is. This can be deleted at some point + // in the future. + if (cpu == llvm::MachO::CPU_TYPE_ARM64 && + sub == llvm::MachO::CPU_SUBTYPE_ARM64E) { + if (GetGDBServerVersion()) + if (m_gdb_server_version >= 1000 && + m_gdb_server_version <= 1504) + sub = 0; + } + } + } else if (name == "triple") { StringExtractor extractor(value); extractor.GetHexByteString(triple); ++num_keys_decoded; - } else if (name.equals("ostype")) { + } else if (name == "ostype") { ParseOSType(value, os_name, environment); ++num_keys_decoded; - } else if (name.equals("vendor")) { + } else if (name == "vendor") { vendor_name = std::string(value); ++num_keys_decoded; - } else if (name.equals("endian")) { + } else if (name == "endian") { byte_order = llvm::StringSwitch<lldb::ByteOrder>(value) .Case("little", eByteOrderLittle) .Case("big", eByteOrderBig) @@ -2150,19 +2179,19 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { .Default(eByteOrderInvalid); if (byte_order != eByteOrderInvalid) ++num_keys_decoded; - } else if (name.equals("ptrsize")) { + } else if (name == "ptrsize") { if (!value.getAsInteger(16, pointer_byte_size)) ++num_keys_decoded; - } else if (name.equals("pid")) { + } else if (name == "pid") { if (!value.getAsInteger(16, pid)) ++num_keys_decoded; - } else if (name.equals("elf_abi")) { + } else if (name == "elf_abi") { elf_abi = std::string(value); ++num_keys_decoded; - } else if (name.equals("main-binary-uuid")) { + } else if (name == "main-binary-uuid") { m_process_standalone_uuid.SetFromStringRef(value); ++num_keys_decoded; - } else if (name.equals("main-binary-slide")) { + } else if (name == "main-binary-slide") { StringExtractor extractor(value); m_process_standalone_value = extractor.GetU64(LLDB_INVALID_ADDRESS, 16); @@ -2170,7 +2199,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { m_process_standalone_value_is_offset = true; ++num_keys_decoded; } - } else if (name.equals("main-binary-address")) { + } else if (name == "main-binary-address") { StringExtractor extractor(value); m_process_standalone_value = extractor.GetU64(LLDB_INVALID_ADDRESS, 16); @@ -2178,7 +2207,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { m_process_standalone_value_is_offset = false; ++num_keys_decoded; } - } else if (name.equals("binary-addresses")) { + } else if (name == "binary-addresses") { m_binary_addresses.clear(); ++num_keys_decoded; for (llvm::StringRef x : llvm::split(value, ',')) { @@ -2617,9 +2646,9 @@ bool GDBRemoteCommunicationClient::LaunchGDBServer( llvm::StringRef name; llvm::StringRef value; while (response.GetNameColonValue(name, value)) { - if (name.equals("port")) + if (name == "port") value.getAsInteger(0, port); - else if (name.equals("pid")) + else if (name == "pid") value.getAsInteger(0, pid); else if (name.compare("socket_name") == 0) { StringExtractor extractor(value); @@ -3388,8 +3417,8 @@ bool GDBRemoteCommunicationClient::GetFileExists( return true; } -bool GDBRemoteCommunicationClient::CalculateMD5( - const lldb_private::FileSpec &file_spec, uint64_t &high, uint64_t &low) { +llvm::ErrorOr<llvm::MD5::MD5Result> GDBRemoteCommunicationClient::CalculateMD5( + const lldb_private::FileSpec &file_spec) { std::string path(file_spec.GetPath(false)); lldb_private::StreamString stream; stream.PutCString("vFile:MD5:"); @@ -3398,16 +3427,60 @@ bool GDBRemoteCommunicationClient::CalculateMD5( if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') - return false; + return std::make_error_code(std::errc::illegal_byte_sequence); if (response.GetChar() != ',') - return false; + return std::make_error_code(std::errc::illegal_byte_sequence); if (response.Peek() && *response.Peek() == 'x') - return false; - low = response.GetHexMaxU64(false, UINT64_MAX); - high = response.GetHexMaxU64(false, UINT64_MAX); - return true; - } - return false; + return std::make_error_code(std::errc::no_such_file_or_directory); + + // GDBRemoteCommunicationServerCommon::Handle_vFile_MD5 concatenates low and + // high hex strings. We can't use response.GetHexMaxU64 because that can't + // handle the concatenated hex string. What would happen is parsing the low + // would consume the whole response packet which would give incorrect + // results. Instead, we get the byte string for each low and high hex + // separately, and parse them. + // + // An alternate way to handle this is to change the server to put a + // delimiter between the low/high parts, and change the client to parse the + // delimiter. However, we choose not to do this so existing lldb-servers + // don't have to be patched + + // The checksum is 128 bits encoded as hex + // This means low/high are halves of 64 bits each, in otherwords, 8 bytes. + // Each byte takes 2 hex characters in the response. + const size_t MD5_HALF_LENGTH = sizeof(uint64_t) * 2; + + // Get low part + auto part = + response.GetStringRef().substr(response.GetFilePos(), MD5_HALF_LENGTH); + if (part.size() != MD5_HALF_LENGTH) + return std::make_error_code(std::errc::illegal_byte_sequence); + response.SetFilePos(response.GetFilePos() + part.size()); + + uint64_t low; + if (part.getAsInteger(/*radix=*/16, low)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + // Get high part + part = + response.GetStringRef().substr(response.GetFilePos(), MD5_HALF_LENGTH); + if (part.size() != MD5_HALF_LENGTH) + return std::make_error_code(std::errc::illegal_byte_sequence); + response.SetFilePos(response.GetFilePos() + part.size()); + + uint64_t high; + if (part.getAsInteger(/*radix=*/16, high)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + llvm::MD5::MD5Result result; + llvm::support::endian::write<uint64_t, llvm::endianness::little>( + result.data(), low); + llvm::support::endian::write<uint64_t, llvm::endianness::little>( + result.data() + 8, high); + + return result; + } + return std::make_error_code(std::errc::operation_canceled); } bool GDBRemoteCommunicationClient::AvoidGPackets(ProcessGDBRemote *process) { diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 866b0773d86d..898d176abc34 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -199,6 +199,8 @@ public: std::optional<bool> GetWatchpointReportedAfter(); + WatchpointHardwareFeature GetSupportedWatchpointTypes(); + const ArchSpec &GetHostArchitecture(); std::chrono::seconds GetHostDefaultPacketTimeout(); @@ -390,7 +392,7 @@ public: *command_output, // Pass nullptr if you don't want the command output const Timeout<std::micro> &timeout); - bool CalculateMD5(const FileSpec &file_spec, uint64_t &high, uint64_t &low); + llvm::ErrorOr<llvm::MD5::MD5Result> CalculateMD5(const FileSpec &file_spec); lldb::DataBufferSP ReadRegister( lldb::tid_t tid, @@ -581,6 +583,8 @@ protected: lldb::tid_t m_curr_tid_run = LLDB_INVALID_THREAD_ID; uint32_t m_num_supported_hardware_watchpoints = 0; + WatchpointHardwareFeature m_watchpoint_types = + eWatchpointHardwareFeatureUnknown; uint32_t m_low_mem_addressing_bits = 0; uint32_t m_high_mem_addressing_bits = 0; diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index b4fb5b68dd41..f9d37490e16a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -340,13 +340,13 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( llvm::StringRef value; while (packet.GetNameColonValue(key, value)) { bool success = true; - if (key.equals("name")) { + if (key == "name") { StringExtractor extractor(value); std::string file; extractor.GetHexByteString(file); match_info.GetProcessInfo().GetExecutableFile().SetFile( file, FileSpec::Style::native); - } else if (key.equals("name_match")) { + } else if (key == "name_match") { NameMatch name_match = llvm::StringSwitch<NameMatch>(value) .Case("equals", NameMatch::Equals) .Case("starts_with", NameMatch::StartsWith) @@ -357,40 +357,40 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( match_info.SetNameMatchType(name_match); if (name_match == NameMatch::Ignore) return SendErrorResponse(2); - } else if (key.equals("pid")) { + } else if (key == "pid") { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetProcessID(pid); - } else if (key.equals("parent_pid")) { + } else if (key == "parent_pid") { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; if (value.getAsInteger(0, pid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetParentProcessID(pid); - } else if (key.equals("uid")) { + } else if (key == "uid") { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetUserID(uid); - } else if (key.equals("gid")) { + } else if (key == "gid") { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetGroupID(gid); - } else if (key.equals("euid")) { + } else if (key == "euid") { uint32_t uid = UINT32_MAX; if (value.getAsInteger(0, uid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveUserID(uid); - } else if (key.equals("egid")) { + } else if (key == "egid") { uint32_t gid = UINT32_MAX; if (value.getAsInteger(0, gid)) return SendErrorResponse(2); match_info.GetProcessInfo().SetEffectiveGroupID(gid); - } else if (key.equals("all_users")) { + } else if (key == "all_users") { match_info.SetMatchAllUsers( OptionArgParser::ToBoolean(value, false, &success)); - } else if (key.equals("triple")) { + } else if (key == "triple") { match_info.GetProcessInfo().GetArchitecture() = HostInfo::GetAugmentedArchSpec(value); } else { @@ -472,7 +472,7 @@ GDBRemoteCommunicationServerCommon::Handle_qSpeedTest( llvm::StringRef key; llvm::StringRef value; bool success = packet.GetNameColonValue(key, value); - if (success && key.equals("response_size")) { + if (success && key == "response_size") { uint32_t response_size = 0; if (!value.getAsInteger(0, response_size)) { if (response_size == 0) diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 3d37bb226a65..08d5f5039d51 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -2087,7 +2087,7 @@ void GDBRemoteCommunicationServerLLGS::AddProcessThreads( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( StringExtractorGDBRemote &packet) { - assert(m_debugged_processes.size() == 1 || + assert(m_debugged_processes.size() <= 1 || bool(m_extensions_supported & NativeProcessProtocol::Extension::multiprocess)); @@ -3083,6 +3083,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { if (registers_count) response.IndentMore(); + llvm::StringSet<> field_enums_seen; for (int reg_index = 0; reg_index < registers_count; reg_index++) { const RegisterInfo *reg_info = reg_context.GetRegisterInfoAtIndex(reg_index); @@ -3096,6 +3097,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { if (reg_info->flags_type) { response.IndentMore(); + reg_info->flags_type->EnumsToXML(response, field_enums_seen); reg_info->flags_type->ToXML(response); response.IndentLess(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index 391abdae2752..65f1cc12ba30 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -46,11 +46,13 @@ using namespace lldb_private; GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port, uint16_t max_port) { + assert(min_port); for (; min_port < max_port; ++min_port) m_port_map[min_port] = LLDB_INVALID_PROCESS_ID; } void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) { + assert(port); // Do not modify existing mappings m_port_map.insert({port, LLDB_INVALID_PROCESS_ID}); } @@ -239,9 +241,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( llvm::StringRef value; std::optional<uint16_t> port; while (packet.GetNameColonValue(name, value)) { - if (name.equals("host")) + if (name == "host") hostname = std::string(value); - else if (name.equals("port")) { + else if (name == "port") { // Make the Optional valid so we can use its value port = 0; value.getAsInteger(0, *port); diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index eb42b9eb6cb6..604c92369e9a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -24,6 +24,7 @@ #include <sys/types.h> #include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Breakpoint/WatchpointAlgorithms.h" #include "lldb/Breakpoint/WatchpointResource.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -262,10 +263,9 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(), m_max_memory_size(0), m_remote_stub_max_memory_size(0), m_addr_to_mmap_size(), m_thread_create_bp_sp(), - m_waiting_for_attach(false), - m_command_sp(), m_breakpoint_pc_offset(0), + m_waiting_for_attach(false), m_command_sp(), m_breakpoint_pc_offset(0), m_initial_tid(LLDB_INVALID_THREAD_ID), m_allow_flash_writes(false), - m_erased_flash_ranges(), m_vfork_in_progress(false) { + m_erased_flash_ranges(), m_vfork_in_progress_count(0) { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, @@ -448,20 +448,20 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { DynamicRegisterInfo::Register reg_info; while (response.GetNameColonValue(name, value)) { - if (name.equals("name")) { + if (name == "name") { reg_info.name.SetString(value); - } else if (name.equals("alt-name")) { + } else if (name == "alt-name") { reg_info.alt_name.SetString(value); - } else if (name.equals("bitsize")) { + } else if (name == "bitsize") { if (!value.getAsInteger(0, reg_info.byte_size)) reg_info.byte_size /= CHAR_BIT; - } else if (name.equals("offset")) { + } else if (name == "offset") { value.getAsInteger(0, reg_info.byte_offset); - } else if (name.equals("encoding")) { + } else if (name == "encoding") { const Encoding encoding = Args::StringToEncoding(value); if (encoding != eEncodingInvalid) reg_info.encoding = encoding; - } else if (name.equals("format")) { + } else if (name == "format") { if (!OptionArgParser::ToFormat(value.str().c_str(), reg_info.format, nullptr) .Success()) reg_info.format = @@ -480,17 +480,17 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { .Case("vector-uint64", eFormatVectorOfUInt64) .Case("vector-uint128", eFormatVectorOfUInt128) .Default(eFormatInvalid); - } else if (name.equals("set")) { + } else if (name == "set") { reg_info.set_name.SetString(value); - } else if (name.equals("gcc") || name.equals("ehframe")) { + } else if (name == "gcc" || name == "ehframe") { value.getAsInteger(0, reg_info.regnum_ehframe); - } else if (name.equals("dwarf")) { + } else if (name == "dwarf") { value.getAsInteger(0, reg_info.regnum_dwarf); - } else if (name.equals("generic")) { + } else if (name == "generic") { reg_info.regnum_generic = Args::StringToGenericRegister(value); - } else if (name.equals("container-regs")) { + } else if (name == "container-regs") { SplitCommaSeparatedRegisterNumberString(value, reg_info.value_regs, 16); - } else if (name.equals("invalidate-regs")) { + } else if (name == "invalidate-regs") { SplitCommaSeparatedRegisterNumberString(value, reg_info.invalidate_regs, 16); } } @@ -900,7 +900,7 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { } AddressableBits addressable_bits = m_gdb_comm.GetAddressableBits(); - addressable_bits.SetProcessMasks(*this); + SetAddressableBitMasks(addressable_bits); if (process_arch.IsValid()) { const ArchSpec &target_arch = GetTarget().GetArchitecture(); @@ -1089,7 +1089,8 @@ Status ProcessGDBRemote::DoAttachToProcessWithID( const int packet_len = ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); SetID(attach_pid); - auto data_sp = std::make_shared<EventDataBytes>(packet, packet_len); + auto data_sp = + std::make_shared<EventDataBytes>(llvm::StringRef(packet, packet_len)); m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp); } else SetExitStatus(-1, error.AsCString()); @@ -1127,8 +1128,7 @@ Status ProcessGDBRemote::DoAttachToProcessWithName( endian::InlHostByteOrder(), endian::InlHostByteOrder()); - auto data_sp = std::make_shared<EventDataBytes>(packet.GetString().data(), - packet.GetSize()); + auto data_sp = std::make_shared<EventDataBytes>(packet.GetString()); m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp); } else @@ -1374,8 +1374,8 @@ Status ProcessGDBRemote::DoResume() { return error; } - auto data_sp = std::make_shared<EventDataBytes>( - continue_packet.GetString().data(), continue_packet.GetSize()); + auto data_sp = + std::make_shared<EventDataBytes>(continue_packet.GetString()); m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue, data_sp); if (!listener_sp->GetEvent(event_sp, std::chrono::seconds(5))) { @@ -1599,6 +1599,26 @@ bool ProcessGDBRemote::CalculateThreadStopInfo(ThreadGDBRemote *thread) { // has no stop reason. thread->GetRegisterContext()->InvalidateIfNeeded(true); if (!GetThreadStopInfoFromJSON(thread, m_jstopinfo_sp)) { + // If a thread is stopped at a breakpoint site, set that as the stop + // reason even if it hasn't executed the breakpoint instruction yet. + // We will silently step over the breakpoint when we resume execution + // and miss the fact that this thread hit the breakpoint. + const size_t num_thread_ids = m_thread_ids.size(); + for (size_t i = 0; i < num_thread_ids; i++) { + if (m_thread_ids[i] == thread->GetID() && m_thread_pcs.size() > i) { + addr_t pc = m_thread_pcs[i]; + lldb::BreakpointSiteSP bp_site_sp = + thread->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); + if (bp_site_sp) { + if (bp_site_sp->ValidForThisThread(*thread)) { + thread->SetStopInfo( + StopInfo::CreateStopReasonWithBreakpointSiteID( + *thread, bp_site_sp->GetID())); + return true; + } + } + } + } thread->SetStopInfo(StopInfoSP()); } return true; @@ -1721,7 +1741,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( } else { bool handled = false; bool did_exec = false; - if (!reason.empty()) { + // debugserver can send reason = "none" which is equivalent + // to no reason. + if (!reason.empty() && reason != "none") { if (reason == "trace") { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = @@ -1863,11 +1885,10 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - // If the current pc is a breakpoint site then the StopInfo should be - // set to Breakpoint even though the remote stub did not set it as such. - // This can happen when the thread is involuntarily interrupted (e.g. - // due to stops on other threads) just as it is about to execute the - // breakpoint instruction. + // If a thread is stopped at a breakpoint site, set that as the stop + // reason even if it hasn't executed the breakpoint instruction yet. + // We will silently step over the breakpoint when we resume execution + // and miss the fact that this thread hit the breakpoint. if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { thread_sp->SetStopInfo(StopInfo::CreateStopReasonWithBreakpointSiteID( *thread_sp, bp_site_sp->GetID())); @@ -2316,7 +2337,7 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } } - addressable_bits.SetProcessMasks(*this); + SetAddressableBitMasks(addressable_bits); ThreadSP thread_sp = SetThreadStopInfo( tid, expedited_register_map, signo, thread_name, reason, description, @@ -3153,23 +3174,13 @@ Status ProcessGDBRemote::EnableWatchpoint(WatchpointSP wp_sp, bool notify) { bool write = wp_sp->WatchpointWrite() || wp_sp->WatchpointModify(); size_t size = wp_sp->GetByteSize(); - // New WatchpointResources needed to implement this Watchpoint. - std::vector<WatchpointResourceSP> resources; - - // LWP_TODO: Break up the user's request into pieces that can be watched - // given the capabilities of the target cpu / stub software. - // As a default, breaking the watched region up into target-pointer-sized, - // aligned, groups. - // - // Beyond the default, a stub can / should inform us of its capabilities, - // e.g. a stub that can do AArch64 power-of-2 MASK watchpoints. - // - // And the cpu may have unique capabilities. AArch64 BAS watchpoints - // can watch any sequential bytes in a doubleword, but Intel watchpoints - // can only watch 1, 2, 4, 8 bytes within a doubleword. - WatchpointResourceSP wp_res_sp = - std::make_shared<WatchpointResource>(addr, size, read, write); - resources.push_back(wp_res_sp); + ArchSpec target_arch = GetTarget().GetArchitecture(); + WatchpointHardwareFeature supported_features = + m_gdb_comm.GetSupportedWatchpointTypes(); + + std::vector<WatchpointResourceSP> resources = + WatchpointAlgorithms::AtomizeWatchpointRequest( + addr, size, read, write, supported_features, target_arch); // LWP_TODO: Now that we know the WP Resources needed to implement this // Watchpoint, we need to look at currently allocated Resources in the @@ -4168,21 +4179,134 @@ struct GdbServerTargetInfo { RegisterSetMap reg_set_map; }; -static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node, - unsigned size) { +static FieldEnum::Enumerators ParseEnumEvalues(const XMLNode &enum_node) { + Log *log(GetLog(GDBRLog::Process)); + // We will use the last instance of each value. Also we preserve the order + // of declaration in the XML, as it may not be numerical. + // For example, hardware may intially release with two states that softwware + // can read from a register field: + // 0 = startup, 1 = running + // If in a future hardware release, the designers added a pre-startup state: + // 0 = startup, 1 = running, 2 = pre-startup + // Now it makes more sense to list them in this logical order as opposed to + // numerical order: + // 2 = pre-startup, 1 = startup, 0 = startup + // This only matters for "register info" but let's trust what the server + // chose regardless. + std::map<uint64_t, FieldEnum::Enumerator> enumerators; + + enum_node.ForEachChildElementWithName( + "evalue", [&enumerators, &log](const XMLNode &enumerator_node) { + std::optional<llvm::StringRef> name; + std::optional<uint64_t> value; + + enumerator_node.ForEachAttribute( + [&name, &value, &log](const llvm::StringRef &attr_name, + const llvm::StringRef &attr_value) { + if (attr_name == "name") { + if (attr_value.size()) + name = attr_value; + else + LLDB_LOG(log, "ProcessGDBRemote::ParseEnumEvalues " + "Ignoring empty name in evalue"); + } else if (attr_name == "value") { + uint64_t parsed_value = 0; + if (llvm::to_integer(attr_value, parsed_value)) + value = parsed_value; + else + LLDB_LOG(log, + "ProcessGDBRemote::ParseEnumEvalues " + "Invalid value \"{0}\" in " + "evalue", + attr_value.data()); + } else + LLDB_LOG(log, + "ProcessGDBRemote::ParseEnumEvalues Ignoring " + "unknown attribute " + "\"{0}\" in evalue", + attr_name.data()); + + // Keep walking attributes. + return true; + }); + + if (value && name) + enumerators.insert_or_assign( + *value, FieldEnum::Enumerator(*value, name->str())); + + // Find all evalue elements. + return true; + }); + + FieldEnum::Enumerators final_enumerators; + for (auto [_, enumerator] : enumerators) + final_enumerators.push_back(enumerator); + + return final_enumerators; +} + +static void +ParseEnums(XMLNode feature_node, + llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) { + Log *log(GetLog(GDBRLog::Process)); + + // The top level element is "<enum...". + feature_node.ForEachChildElementWithName( + "enum", [log, ®isters_enum_types](const XMLNode &enum_node) { + std::string id; + + enum_node.ForEachAttribute([&id](const llvm::StringRef &attr_name, + const llvm::StringRef &attr_value) { + if (attr_name == "id") + id = attr_value; + + // There is also a "size" attribute that is supposed to be the size in + // bytes of the register this applies to. However: + // * LLDB doesn't need this information. + // * It is difficult to verify because you have to wait until the + // enum is applied to a field. + // + // So we will emit this attribute in XML for GDB's sake, but will not + // bother ingesting it. + + // Walk all attributes. + return true; + }); + + if (!id.empty()) { + FieldEnum::Enumerators enumerators = ParseEnumEvalues(enum_node); + if (!enumerators.empty()) { + LLDB_LOG(log, + "ProcessGDBRemote::ParseEnums Found enum type \"{0}\"", + id); + registers_enum_types.insert_or_assign( + id, std::make_unique<FieldEnum>(id, enumerators)); + } + } + + // Find all <enum> elements. + return true; + }); +} + +static std::vector<RegisterFlags::Field> ParseFlagsFields( + XMLNode flags_node, unsigned size, + const llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) { Log *log(GetLog(GDBRLog::Process)); const unsigned max_start_bit = size * 8 - 1; // Process the fields of this set of flags. std::vector<RegisterFlags::Field> fields; - flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, - &log](const XMLNode - &field_node) { + flags_node.ForEachChildElementWithName("field", [&fields, max_start_bit, &log, + ®isters_enum_types]( + const XMLNode + &field_node) { std::optional<llvm::StringRef> name; std::optional<unsigned> start; std::optional<unsigned> end; + std::optional<llvm::StringRef> type; - field_node.ForEachAttribute([&name, &start, &end, max_start_bit, + field_node.ForEachAttribute([&name, &start, &end, &type, max_start_bit, &log](const llvm::StringRef &attr_name, const llvm::StringRef &attr_value) { // Note that XML in general requires that each of these attributes only @@ -4229,8 +4353,7 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node, attr_value.data()); } } else if (attr_name == "type") { - // Type is a known attribute but we do not currently use it and it is - // not required. + type = attr_value; } else { LLDB_LOG( log, @@ -4243,14 +4366,55 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node, }); if (name && start && end) { - if (*start > *end) { + if (*start > *end) LLDB_LOG( log, "ProcessGDBRemote::ParseFlagsFields Start {0} > end {1} in field " "\"{2}\", ignoring", *start, *end, name->data()); - } else { - fields.push_back(RegisterFlags::Field(name->str(), *start, *end)); + else { + if (RegisterFlags::Field::GetSizeInBits(*start, *end) > 64) + LLDB_LOG(log, + "ProcessGDBRemote::ParseFlagsFields Ignoring field \"{2}\" " + "that has " + "size > 64 bits, this is not supported", + name->data()); + else { + // A field's type may be set to the name of an enum type. + const FieldEnum *enum_type = nullptr; + if (type && !type->empty()) { + auto found = registers_enum_types.find(*type); + if (found != registers_enum_types.end()) { + enum_type = found->second.get(); + + // No enumerator can exceed the range of the field itself. + uint64_t max_value = + RegisterFlags::Field::GetMaxValue(*start, *end); + for (const auto &enumerator : enum_type->GetEnumerators()) { + if (enumerator.m_value > max_value) { + enum_type = nullptr; + LLDB_LOG( + log, + "ProcessGDBRemote::ParseFlagsFields In enum \"{0}\" " + "evalue \"{1}\" with value {2} exceeds the maximum value " + "of field \"{3}\" ({4}), ignoring enum", + type->data(), enumerator.m_name, enumerator.m_value, + name->data(), max_value); + break; + } + } + } else { + LLDB_LOG(log, + "ProcessGDBRemote::ParseFlagsFields Could not find type " + "\"{0}\" " + "for field \"{1}\", ignoring", + type->data(), name->data()); + } + } + + fields.push_back( + RegisterFlags::Field(name->str(), *start, *end, enum_type)); + } } } @@ -4261,12 +4425,14 @@ static std::vector<RegisterFlags::Field> ParseFlagsFields(XMLNode flags_node, void ParseFlags( XMLNode feature_node, - llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types) { + llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types, + const llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) { Log *log(GetLog(GDBRLog::Process)); feature_node.ForEachChildElementWithName( "flags", - [&log, ®isters_flags_types](const XMLNode &flags_node) -> bool { + [&log, ®isters_flags_types, + ®isters_enum_types](const XMLNode &flags_node) -> bool { LLDB_LOG(log, "ProcessGDBRemote::ParseFlags Found flags node \"{0}\"", flags_node.GetAttributeValue("id").c_str()); @@ -4299,7 +4465,7 @@ void ParseFlags( if (id && size) { // Process the fields of this set of flags. std::vector<RegisterFlags::Field> fields = - ParseFlagsFields(flags_node, *size); + ParseFlagsFields(flags_node, *size, registers_enum_types); if (fields.size()) { // Sort so that the fields with the MSBs are first. std::sort(fields.rbegin(), fields.rend()); @@ -4364,15 +4530,21 @@ void ParseFlags( bool ParseRegisters( XMLNode feature_node, GdbServerTargetInfo &target_info, std::vector<DynamicRegisterInfo::Register> ®isters, - llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types) { + llvm::StringMap<std::unique_ptr<RegisterFlags>> ®isters_flags_types, + llvm::StringMap<std::unique_ptr<FieldEnum>> ®isters_enum_types) { if (!feature_node) return false; Log *log(GetLog(GDBRLog::Process)); - ParseFlags(feature_node, registers_flags_types); + // Enums first because they are referenced by fields in the flags. + ParseEnums(feature_node, registers_enum_types); + for (const auto &enum_type : registers_enum_types) + enum_type.second->DumpToLog(log); + + ParseFlags(feature_node, registers_flags_types, registers_enum_types); for (const auto &flags : registers_flags_types) - flags.second->log(log); + flags.second->DumpToLog(log); feature_node.ForEachChildElementWithName( "reg", @@ -4620,6 +4792,8 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( // We don't have any information about vendor or OS. arch_to_use.SetTriple(llvm::StringSwitch<std::string>(target_info.arch) .Case("i386:x86-64", "x86_64") + .Case("riscv:rv64", "riscv64") + .Case("riscv:rv32", "riscv32") .Default(target_info.arch) + "--"); @@ -4630,7 +4804,7 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( if (arch_to_use.IsValid()) { for (auto &feature_node : feature_nodes) { ParseRegisters(feature_node, target_info, registers, - m_registers_flags_types); + m_registers_flags_types, m_registers_enum_types); } for (const auto &include : target_info.includes) { @@ -4695,16 +4869,19 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { if (!m_gdb_comm.GetQXferFeaturesReadSupported()) return false; - // This holds register flags information for the whole of target.xml. + // These hold register type information for the whole of target.xml. // target.xml may include further documents that // GetGDBServerRegisterInfoXMLAndProcess will recurse to fetch and process. // That's why we clear the cache here, and not in // GetGDBServerRegisterInfoXMLAndProcess. To prevent it being cleared on every // include read. m_registers_flags_types.clear(); + m_registers_enum_types.clear(); std::vector<DynamicRegisterInfo::Register> registers; if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml", - registers)) + registers) && + // Target XML is not required to include register information. + !registers.empty()) AddRemoteRegisters(registers, arch_to_use); return m_register_info_sp->GetNumRegisters() > 0; @@ -5069,7 +5246,7 @@ std::string ProcessGDBRemote::HarmonizeThreadIdsForProfileData( llvm::StringRef usec_name, usec_value; uint32_t input_file_pos = profileDataExtractor.GetFilePos(); if (profileDataExtractor.GetNameColonValue(usec_name, usec_value)) { - if (usec_name.equals("thread_used_usec")) { + if (usec_name == "thread_used_usec") { has_used_usec = true; usec_value.getAsInteger(0, curr_used_usec); } else { @@ -5279,8 +5456,10 @@ public: (ProcessGDBRemote *)m_interpreter.GetExecutionContext() .GetProcessPtr(); if (process) { - StreamSP output_stream_sp( - m_interpreter.GetDebugger().GetAsyncOutputStream()); + StreamSP output_stream_sp = result.GetImmediateOutputStream(); + if (!output_stream_sp) + output_stream_sp = + StreamSP(m_interpreter.GetDebugger().GetAsyncOutputStream()); result.SetImmediateOutputStream(output_stream_sp); const uint32_t num_packets = @@ -5340,8 +5519,7 @@ public: interpreter, "process plugin packet xfer-size", "Maximum size that lldb will try to read/write one one chunk.", nullptr) { - CommandArgumentData max_arg{eArgTypeUnsignedInteger, eArgRepeatPlain}; - m_arguments.push_back({max_arg}); + AddSimpleArgumentList(eArgTypeUnsignedInteger); } ~CommandObjectProcessGDBRemotePacketXferSize() override = default; @@ -5383,8 +5561,7 @@ public: "be added to the packet prior to sending and " "stripped from the result.", nullptr) { - CommandArgumentData packet_arg{eArgTypeNone, eArgRepeatStar}; - m_arguments.push_back({packet_arg}); + AddSimpleArgumentList(eArgTypeNone, eArgRepeatStar); } ~CommandObjectProcessGDBRemotePacketSend() override = default; @@ -5622,8 +5799,11 @@ void ProcessGDBRemote::DidFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { Log *log = GetLog(GDBRLog::Process); - assert(!m_vfork_in_progress); - m_vfork_in_progress = true; + LLDB_LOG( + log, + "ProcessGDBRemote::DidFork() called for child_pid: {0}, child_tid {1}", + child_pid, child_tid); + ++m_vfork_in_progress_count; // Disable all software breakpoints for the duration of vfork. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) @@ -5677,8 +5857,8 @@ void ProcessGDBRemote::DidVFork(lldb::pid_t child_pid, lldb::tid_t child_tid) { } void ProcessGDBRemote::DidVForkDone() { - assert(m_vfork_in_progress); - m_vfork_in_progress = false; + assert(m_vfork_in_progress_count > 0); + --m_vfork_in_progress_count; // Reenable all software breakpoints that were enabled before vfork. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) @@ -5688,7 +5868,9 @@ void ProcessGDBRemote::DidVForkDone() { void ProcessGDBRemote::DidExec() { // If we are following children, vfork is finished by exec (rather than // vforkdone that is submitted for parent). - if (GetFollowForkMode() == eFollowChild) - m_vfork_in_progress = false; + if (GetFollowForkMode() == eFollowChild) { + if (m_vfork_in_progress_count > 0) + --m_vfork_in_progress_count; + } Process::DidExec(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index c1ea1cc79055..b44ffefcd0d3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -301,7 +301,8 @@ protected: using FlashRange = FlashRangeVector::Entry; FlashRangeVector m_erased_flash_ranges; - bool m_vfork_in_progress; + // Number of vfork() operations being handled. + uint32_t m_vfork_in_progress_count; // Accessors bool IsRunning(lldb::StateType state) { @@ -483,6 +484,11 @@ private: // entries are added. Which would invalidate any pointers set in the register // info up to that point. llvm::StringMap<std::unique_ptr<RegisterFlags>> m_registers_flags_types; + + // Enum types are referenced by register fields. This does not store the data + // directly because the map may reallocate. Pointers to these are contained + // within instances of RegisterFlags. + llvm::StringMap<std::unique_ptr<FieldEnum>> m_registers_enum_types; }; } // namespace process_gdb_remote diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index b72307c7e4b9..13599f4a1553 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -156,7 +156,7 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file, DataBufferSP core_data) - : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file), + : PostMortemProcess(target_sp, listener_sp, core_file), m_core_data(std::move(core_data)), m_active_exception(nullptr), m_is_wow64(false) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index 0e4e52c0113f..3f3123a0a8b5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/contrib/llvm-project/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -107,7 +107,6 @@ protected: JITLoaderList &GetJITLoaders() override; private: - FileSpec m_core_file; lldb::DataBufferSP m_core_data; llvm::ArrayRef<minidump::Thread> m_thread_list; const minidump::ExceptionStream *m_active_exception; diff --git a/contrib/llvm-project/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp b/contrib/llvm-project/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp index 0aaddad53126..0fb5490defc6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/REPL/Clang/ClangREPL.cpp @@ -95,7 +95,9 @@ bool ClangREPL::PrintOneVariable(Debugger &debugger, if (m_implicit_expr_result_regex.Execute(var->GetName().GetStringRef())) return true; } - valobj_sp->Dump(*output_sp); + if (llvm::Error error = valobj_sp->Dump(*output_sp)) + *output_sp << "error: " << toString(std::move(error)); + return true; } diff --git a/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp b/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp index 067768537c06..1ecde7bee582 100644 --- a/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp @@ -43,8 +43,7 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType( ScratchTypeSystemClang::GetForTarget(m_target); assert(type_system); - std::string register_type_name = "__lldb_register_fields_"; - register_type_name += name; + std::string register_type_name = "__lldb_register_fields_" + name; // See if we have made this type before and can reuse it. CompilerType fields_type = type_system->GetTypeForIdentifier<clang::CXXRecordDecl>( @@ -67,8 +66,48 @@ CompilerType RegisterTypeBuilderClang::GetRegisterType( // We assume that RegisterFlags has padded and sorted the fields // already. for (const RegisterFlags::Field &field : flags.GetFields()) { + CompilerType field_type = field_uint_type; + + if (const FieldEnum *enum_type = field.GetEnum()) { + const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators(); + if (!enumerators.empty()) { + // Enums can be used by many registers and the size of each register + // may be different. The register size is used as the underlying size + // of the enumerators, so we must make one enum type per register size + // it is used with. + std::string enum_type_name = "__lldb_register_fields_enum_" + + enum_type->GetID() + "_" + + std::to_string(byte_size); + + // Enums can be used by mutiple fields and multiple registers, so we + // may have built this one already. + CompilerType field_enum_type = + type_system->GetTypeForIdentifier<clang::EnumDecl>( + enum_type_name); + + if (field_enum_type) + field_type = field_enum_type; + else { + field_type = type_system->CreateEnumerationType( + enum_type_name, type_system->GetTranslationUnitDecl(), + OptionalClangModuleID(), Declaration(), field_uint_type, false); + + type_system->StartTagDeclarationDefinition(field_type); + + Declaration decl; + for (auto enumerator : enumerators) { + type_system->AddEnumerationValueToEnumerationType( + field_type, decl, enumerator.m_name.c_str(), + enumerator.m_value, byte_size * 8); + } + + type_system->CompleteTagDeclarationDefinition(field_type); + } + } + } + type_system->AddFieldToRecordType(fields_type, field.GetName(), - field_uint_type, lldb::eAccessPublic, + field_type, lldb::eAccessPublic, field.GetSizeInBits()); } diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp index 9ba4731032bd..6e93bec80056 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPlatformPythonInterface.cpp @@ -20,6 +20,8 @@ #include "../ScriptInterpreterPythonImpl.h" #include "ScriptedPlatformPythonInterface.h" +#include "lldb/Target/ExecutionContext.h" + using namespace lldb; using namespace lldb_private; using namespace lldb_private::python; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp index e86b34d6b930..313c597ce48f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedProcessPythonInterface.cpp @@ -49,7 +49,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetCapabilities() { StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>("get_capabilities", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) return {}; return dict; @@ -90,7 +91,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetThreadsInfo() { StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>("get_threads_info", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) return {}; return dict; @@ -106,7 +108,8 @@ bool ScriptedProcessPythonInterface::CreateBreakpoint(lldb::addr_t addr, if (py_error.Fail()) error = py_error; - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetBooleanValue(); @@ -131,7 +134,8 @@ lldb::offset_t ScriptedProcessPythonInterface::WriteMemoryAtAddress( StructuredData::ObjectSP obj = Dispatch("write_memory_at_address", py_error, addr, data_sp, error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return LLDB_INVALID_OFFSET; // If there was an error on the python call, surface it to the user. @@ -146,7 +150,8 @@ StructuredData::ArraySP ScriptedProcessPythonInterface::GetLoadedImages() { StructuredData::ArraySP array = Dispatch<StructuredData::ArraySP>("get_loaded_images", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, array, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, array, + error)) return {}; return array; @@ -156,7 +161,8 @@ lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { Status error; StructuredData::ObjectSP obj = Dispatch("get_process_id", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return LLDB_INVALID_PROCESS_ID; return obj->GetUnsignedIntegerValue(LLDB_INVALID_PROCESS_ID); @@ -166,7 +172,8 @@ bool ScriptedProcessPythonInterface::IsAlive() { Status error; StructuredData::ObjectSP obj = Dispatch("is_alive", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetBooleanValue(); @@ -177,7 +184,8 @@ ScriptedProcessPythonInterface::GetScriptedThreadPluginName() { Status error; StructuredData::ObjectSP obj = Dispatch("get_scripted_thread_plugin", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetStringValue().str(); @@ -193,7 +201,8 @@ StructuredData::DictionarySP ScriptedProcessPythonInterface::GetMetadata() { StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>("get_process_metadata", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) return {}; return dict; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp index 6f22503b279c..699412e437a1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp @@ -48,13 +48,35 @@ Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( if (lldb::SBError *sb_error = reinterpret_cast<lldb::SBError *>( python::LLDBSWIGPython_CastPyObjectToSBError(p.get()))) return m_interpreter.GetStatusFromSBError(*sb_error); - else - error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); + error.SetErrorString("Couldn't cast lldb::SBError to lldb::Status."); return {}; } template <> +Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( + python::PythonObject &p, Status &error) { + if (lldb::SBEvent *sb_event = reinterpret_cast<lldb::SBEvent *>( + python::LLDBSWIGPython_CastPyObjectToSBEvent(p.get()))) + return m_interpreter.GetOpaqueTypeFromSBEvent(*sb_event); + error.SetErrorString("Couldn't cast lldb::SBEvent to lldb_private::Event."); + + return nullptr; +} + +template <> +lldb::StreamSP +ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( + python::PythonObject &p, Status &error) { + if (lldb::SBStream *sb_stream = reinterpret_cast<lldb::SBStream *>( + python::LLDBSWIGPython_CastPyObjectToSBStream(p.get()))) + return m_interpreter.GetOpaqueTypeFromSBStream(*sb_stream); + error.SetErrorString("Couldn't cast lldb::SBStream to lldb_private::Stream."); + + return nullptr; +} + +template <> lldb::DataExtractorSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( python::PythonObject &p, Status &error) { diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index 163659234466..e1a3156d10af 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -115,7 +115,7 @@ public: PythonObject::ResolveNameWithDictionary<python::PythonCallable>( class_name, dict); if (!init.IsAllocated()) - return create_error(llvm::formatv("Could not find script class: %s", + return create_error(llvm::formatv("Could not find script class: {0}", class_name.data())); std::tuple<Args...> original_args = std::forward_as_tuple(args...); @@ -248,8 +248,11 @@ protected: (PyObject *)m_object_instance_sp->GetValue()); if (!implementor.IsAllocated()) - return ErrorWithMessage<T>(caller_signature, - "Python implementor not allocated.", error); + return llvm::is_contained(GetAbstractMethods(), method_name) + ? ErrorWithMessage<T>(caller_signature, + "Python implementor not allocated.", + error) + : T{}; std::tuple<Args...> original_args = std::forward_as_tuple(args...); auto transformed_args = TransformArgs(original_args); @@ -322,6 +325,10 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(lldb::ThreadPlanSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessAttachInfoSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -330,6 +337,14 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(Event *arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + + python::PythonObject Transform(lldb::StreamSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg.get()); + } + python::PythonObject Transform(lldb::DataExtractorSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -428,6 +443,15 @@ Status ScriptedPythonInterface::ExtractValueFromPythonObject<Status>( python::PythonObject &p, Status &error); template <> +Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( + python::PythonObject &p, Status &error); + +template <> +lldb::StreamSP +ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( + python::PythonObject &p, Status &error); + +template <> lldb::BreakpointSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::BreakpointSP>( python::PythonObject &p, Status &error); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp new file mode 100644 index 000000000000..f23858c01277 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.cpp @@ -0,0 +1,105 @@ +//===-- ScriptedThreadPlanPythonInterface.cpp -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/Config.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 "ScriptedThreadPlanPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; + +ScriptedThreadPlanPythonInterface::ScriptedThreadPlanPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedThreadPlanInterface(), ScriptedPythonInterface(interpreter) {} + +llvm::Expected<StructuredData::GenericSP> +ScriptedThreadPlanPythonInterface::CreatePluginObject( + const llvm::StringRef class_name, lldb::ThreadPlanSP thread_plan_sp, + const StructuredDataImpl &args_sp) { + return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, + thread_plan_sp, args_sp); +} + +llvm::Expected<bool> +ScriptedThreadPlanPythonInterface::ExplainsStop(Event *event) { + Status error; + StructuredData::ObjectSP obj = Dispatch("explains_stop", error, event); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + if (!obj) + return false; + return error.ToError(); + } + + return obj->GetBooleanValue(); +} + +llvm::Expected<bool> +ScriptedThreadPlanPythonInterface::ShouldStop(Event *event) { + Status error; + StructuredData::ObjectSP obj = Dispatch("should_stop", error, event); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + if (!obj) + return false; + return error.ToError(); + } + + return obj->GetBooleanValue(); +} + +llvm::Expected<bool> ScriptedThreadPlanPythonInterface::IsStale() { + Status error; + StructuredData::ObjectSP obj = Dispatch("is_stale", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + if (!obj) + return false; + return error.ToError(); + } + + return obj->GetBooleanValue(); +} + +lldb::StateType ScriptedThreadPlanPythonInterface::GetRunState() { + Status error; + StructuredData::ObjectSP obj = Dispatch("should_step", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) + return lldb::eStateStepping; + + return static_cast<lldb::StateType>(obj->GetUnsignedIntegerValue( + static_cast<uint32_t>(lldb::eStateStepping))); +} + +llvm::Error +ScriptedThreadPlanPythonInterface::GetStopDescription(lldb::StreamSP &stream) { + Status error; + Dispatch("stop_description", error, stream); + + if (error.Fail()) + return error.ToError(); + + return llvm::Error::success(); +} + +#endif diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h new file mode 100644 index 000000000000..6ec89b9f5925 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPlanPythonInterface.h @@ -0,0 +1,48 @@ +//===-- ScriptedThreadPlanPythonInterface.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_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedPythonInterface.h" +#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h" +#include <optional> + +namespace lldb_private { +class ScriptedThreadPlanPythonInterface : public ScriptedThreadPlanInterface, + public ScriptedPythonInterface { +public: + ScriptedThreadPlanPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(const llvm::StringRef class_name, + lldb::ThreadPlanSP thread_plan_sp, + const StructuredDataImpl &args_sp) override; + + llvm::SmallVector<llvm::StringLiteral> GetAbstractMethods() const override { + return {}; + } + + llvm::Expected<bool> ExplainsStop(Event *event) override; + + llvm::Expected<bool> ShouldStop(Event *event) override; + + llvm::Expected<bool> IsStale() override; + + lldb::StateType GetRunState() override; + + llvm::Error GetStopDescription(lldb::StreamSP &stream) override; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDTHREADPLANPYTHONINTERFACE_H diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp index 18e268527eb2..8af89d761764 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedThreadPythonInterface.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/Log.h" #include "lldb/lldb-enumerations.h" @@ -44,7 +45,8 @@ lldb::tid_t ScriptedThreadPythonInterface::GetThreadID() { Status error; StructuredData::ObjectSP obj = Dispatch("get_thread_id", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return LLDB_INVALID_THREAD_ID; return obj->GetUnsignedIntegerValue(LLDB_INVALID_THREAD_ID); @@ -54,7 +56,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetName() { Status error; StructuredData::ObjectSP obj = Dispatch("get_name", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetStringValue().str(); @@ -64,7 +67,8 @@ lldb::StateType ScriptedThreadPythonInterface::GetState() { Status error; StructuredData::ObjectSP obj = Dispatch("get_state", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return eStateInvalid; return static_cast<StateType>(obj->GetUnsignedIntegerValue(eStateInvalid)); @@ -74,7 +78,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetQueue() { Status error; StructuredData::ObjectSP obj = Dispatch("get_queue", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetStringValue().str(); @@ -85,7 +90,8 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetStopReason() { StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>("get_stop_reason", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) return {}; return dict; @@ -96,7 +102,8 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetStackFrames() { StructuredData::ArraySP arr = Dispatch<StructuredData::ArraySP>("get_stackframes", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, + error)) return {}; return arr; @@ -107,7 +114,8 @@ StructuredData::DictionarySP ScriptedThreadPythonInterface::GetRegisterInfo() { StructuredData::DictionarySP dict = Dispatch<StructuredData::DictionarySP>("get_register_info", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, dict, + error)) return {}; return dict; @@ -117,7 +125,8 @@ std::optional<std::string> ScriptedThreadPythonInterface::GetRegisterContext() { Status error; StructuredData::ObjectSP obj = Dispatch("get_register_context", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) return {}; return obj->GetAsString()->GetValue().str(); @@ -128,7 +137,8 @@ StructuredData::ArraySP ScriptedThreadPythonInterface::GetExtendedInfo() { StructuredData::ArraySP arr = Dispatch<StructuredData::ArraySP>("get_extended_info", error); - if (!CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, error)) + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, arr, + error)) return {}; return arr; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index ea0a1cdff40f..7c7035e0c86c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -61,7 +61,7 @@ Expected<std::string> python::As<std::string>(Expected<PythonObject> &&obj) { if (!obj) return obj.takeError(); PyObject *str_obj = PyObject_Str(obj.get().get()); - if (!obj) + if (!str_obj) return llvm::make_error<PythonException>(); auto str = Take<PythonString>(str_obj); auto utf8 = str.AsUTF8(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 82eee76e42b2..88c1bb7e729e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -194,6 +194,8 @@ template <typename T, char F> struct PassthroughFormat { }; template <> struct PythonFormat<char *> : PassthroughFormat<char *, 's'> {}; +template <> struct PythonFormat<const char *> : + PassthroughFormat<const char *, 's'> {}; template <> struct PythonFormat<char> : PassthroughFormat<char, 'b'> {}; template <> struct PythonFormat<unsigned char> : PassthroughFormat<unsigned char, 'B'> {}; diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 7cdd5577919b..3026b6113ae8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -32,6 +32,7 @@ class SBStream; class SBStructuredData; class SBFileSpec; class SBModuleSpec; +class SBStringList; } // namespace lldb namespace lldb_private { @@ -96,12 +97,14 @@ public: static PythonObject ToSWIGWrapper(lldb::ExecutionContextRefSP ctx_sp); static PythonObject ToSWIGWrapper(const TypeSummaryOptions &summary_options); static PythonObject ToSWIGWrapper(const SymbolContext &sym_ctx); + static PythonObject ToSWIGWrapper(const Stream *stream); + static PythonObject ToSWIGWrapper(std::shared_ptr<lldb::SBStream> stream_sb); + static PythonObject ToSWIGWrapper(Event *event); static PythonObject ToSWIGWrapper(lldb::ProcessAttachInfoSP attach_info_sp); static PythonObject ToSWIGWrapper(lldb::ProcessLaunchInfoSP launch_info_sp); static PythonObject ToSWIGWrapper(lldb::DataExtractorSP data_extractor_sp); - static PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBStream> stream_sb); static PythonObject ToSWIGWrapper(std::unique_ptr<lldb::SBStructuredData> data_sb); static PythonObject @@ -111,7 +114,6 @@ public: static python::ScopedPythonObject<lldb::SBCommandReturnObject> ToSWIGWrapper(CommandReturnObject &cmd_retobj); - static python::ScopedPythonObject<lldb::SBEvent> ToSWIGWrapper(Event *event); // These prototypes are the Pythonic implementations of the required // callbacks. Although these are scripting-language specific, their definition // depends on the public API. @@ -146,21 +148,6 @@ public: const char *session_dictionary_name, lldb::DebuggerSP debugger_sp); - static python::PythonObject LLDBSwigPythonCreateScriptedThreadPlan( - const char *python_class_name, const char *session_dictionary_name, - const StructuredDataImpl &args_data, std::string &error_string, - const lldb::ThreadPlanSP &thread_plan_sp); - - static bool LLDBSWIGPythonCallThreadPlan(void *implementor, - const char *method_name, - lldb_private::Event *event_sp, - bool &got_error); - - static bool LLDBSWIGPythonCallThreadPlan(void *implementor, - const char *method_name, - lldb_private::Stream *stream, - bool &got_error); - static python::PythonObject LLDBSwigPythonCreateScriptedBreakpointResolver( const char *python_class_name, const char *session_dictionary_name, const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp); @@ -212,6 +199,16 @@ public: lldb::DebuggerSP debugger, const char *args, lldb_private::CommandReturnObject &cmd_retobj, lldb::ExecutionContextRefSP exe_ctx_ref_sp); + static bool + LLDBSwigPythonCallParsedCommandObject(PyObject *implementor, + lldb::DebuggerSP debugger, + StructuredDataImpl &args_impl, + lldb_private::CommandReturnObject &cmd_retobj, + lldb::ExecutionContextRefSP exe_ctx_ref_sp); + + static std::optional<std::string> + LLDBSwigPythonGetRepeatCommandForScriptedCommand(PyObject *implementor, + std::string &command); static bool LLDBSwigPythonCallModuleInit(const char *python_module_name, const char *session_dictionary_name, @@ -262,6 +259,8 @@ void *LLDBSWIGPython_CastPyObjectToSBBreakpoint(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBAttachInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data); +void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data); +void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data); } // namespace python diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index ef7a2c128a22..70fa6d83e306 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -17,6 +17,7 @@ #include "Interfaces/OperatingSystemPythonInterface.h" #include "Interfaces/ScriptedPlatformPythonInterface.h" #include "Interfaces/ScriptedProcessPythonInterface.h" +#include "Interfaces/ScriptedThreadPlanPythonInterface.h" #include "Interfaces/ScriptedThreadPythonInterface.h" #include "PythonDataObjects.h" #include "PythonReadline.h" @@ -24,6 +25,7 @@ #include "ScriptInterpreterPythonImpl.h" #include "lldb/API/SBError.h" +#include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBValue.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -96,24 +98,28 @@ public: InitializePythonRAII() { InitializePythonHome(); + // The table of built-in modules can only be extended before Python is + // initialized. + if (!Py_IsInitialized()) { #ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE - // Python's readline is incompatible with libedit being linked into lldb. - // Provide a patched version local to the embedded interpreter. - bool ReadlinePatched = false; - for (auto *p = PyImport_Inittab; p->name != nullptr; p++) { - if (strcmp(p->name, "readline") == 0) { - p->initfunc = initlldb_readline; - break; + // Python's readline is incompatible with libedit being linked into lldb. + // Provide a patched version local to the embedded interpreter. + bool ReadlinePatched = false; + for (auto *p = PyImport_Inittab; p->name != nullptr; p++) { + if (strcmp(p->name, "readline") == 0) { + p->initfunc = initlldb_readline; + break; + } + } + if (!ReadlinePatched) { + PyImport_AppendInittab("readline", initlldb_readline); + ReadlinePatched = true; } - } - if (!ReadlinePatched) { - PyImport_AppendInittab("readline", initlldb_readline); - ReadlinePatched = true; - } #endif - // Register _lldb as a built-in module. - PyImport_AppendInittab("_lldb", LLDBSwigPyInit); + // Register _lldb as a built-in module. + PyImport_AppendInittab("_lldb", LLDBSwigPyInit); + } // Python < 3.2 and Python >= 3.2 reversed the ordering requirements for // calling `Py_Initialize` and `PyEval_InitThreads`. < 3.2 requires that you @@ -531,7 +537,6 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, break; data_up->user_source.SplitIntoLines(data); - StructuredData::ObjectSP empty_args_sp; if (GenerateBreakpointCommandCallbackData(data_up->user_source, data_up->script_source, /*has_extra_args=*/false, @@ -1413,7 +1418,7 @@ bool ScriptInterpreterPythonImpl::GenerateScriptAliasFunction( sstr.Printf("def %s (debugger, args, exe_ctx, result, internal_dict):", auto_generated_function_name.c_str()); - if (!GenerateFunction(sstr.GetData(), user_input, /*is_callback=*/true) + if (!GenerateFunction(sstr.GetData(), user_input, /*is_callback=*/false) .Success()) return false; @@ -1533,6 +1538,11 @@ ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { return std::make_shared<ScriptedThreadPythonInterface>(*this); } +ScriptedThreadPlanInterfaceSP +ScriptInterpreterPythonImpl::CreateScriptedThreadPlanInterface() { + return std::make_shared<ScriptedThreadPlanPythonInterface>(*this); +} + OperatingSystemInterfaceSP ScriptInterpreterPythonImpl::CreateOperatingSystemInterface() { return std::make_shared<OperatingSystemPythonInterface>(*this); @@ -1549,122 +1559,6 @@ ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( return py_obj.CreateStructuredObject(); } -StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( - const char *class_name, const StructuredDataImpl &args_data, - std::string &error_str, lldb::ThreadPlanSP thread_plan_sp) { - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::ObjectSP(); - - if (!thread_plan_sp.get()) - return {}; - - Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); - ScriptInterpreterPythonImpl *python_interpreter = - GetPythonInterpreter(debugger); - - if (!python_interpreter) - return {}; - - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - PythonObject ret_val = SWIGBridge::LLDBSwigPythonCreateScriptedThreadPlan( - class_name, python_interpreter->m_dictionary_name.c_str(), args_data, - error_str, thread_plan_sp); - if (!ret_val) - return {}; - - return StructuredData::ObjectSP( - new StructuredPythonObject(std::move(ret_val))); -} - -bool ScriptInterpreterPythonImpl::ScriptedThreadPlanExplainsStop( - StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) { - bool explains_stop = true; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - explains_stop = SWIGBridge::LLDBSWIGPythonCallThreadPlan( - generic->GetValue(), "explains_stop", event, script_error); - if (script_error) - return true; - } - return explains_stop; -} - -bool ScriptInterpreterPythonImpl::ScriptedThreadPlanShouldStop( - StructuredData::ObjectSP implementor_sp, Event *event, bool &script_error) { - bool should_stop = true; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_stop = SWIGBridge::LLDBSWIGPythonCallThreadPlan( - generic->GetValue(), "should_stop", event, script_error); - if (script_error) - return true; - } - return should_stop; -} - -bool ScriptInterpreterPythonImpl::ScriptedThreadPlanIsStale( - StructuredData::ObjectSP implementor_sp, bool &script_error) { - bool is_stale = true; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - is_stale = SWIGBridge::LLDBSWIGPythonCallThreadPlan( - generic->GetValue(), "is_stale", (Event *)nullptr, script_error); - if (script_error) - return true; - } - return is_stale; -} - -lldb::StateType ScriptInterpreterPythonImpl::ScriptedThreadPlanGetRunState( - StructuredData::ObjectSP implementor_sp, bool &script_error) { - bool should_step = false; - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (generic) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_step = SWIGBridge::LLDBSWIGPythonCallThreadPlan( - generic->GetValue(), "should_step", (Event *)nullptr, script_error); - if (script_error) - should_step = true; - } - if (should_step) - return lldb::eStateStepping; - return lldb::eStateRunning; -} - -bool -ScriptInterpreterPythonImpl::ScriptedThreadPlanGetStopDescription( - StructuredData::ObjectSP implementor_sp, lldb_private::Stream *stream, - bool &script_error) { - StructuredData::Generic *generic = nullptr; - if (implementor_sp) - generic = implementor_sp->GetAsGeneric(); - if (!generic) { - script_error = true; - return false; - } - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - return SWIGBridge::LLDBSWIGPythonCallThreadPlan( - generic->GetValue(), "stop_description", stream, script_error); -} - - StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( const char *class_name, const StructuredDataImpl &args_data, @@ -2490,8 +2384,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( auto ExtendSysPath = [&](std::string directory) -> llvm::Error { if (directory.empty()) { - return llvm::make_error<llvm::StringError>( - "invalid directory name", llvm::inconvertibleErrorCode()); + return llvm::createStringError("invalid directory name"); } replace_all(directory, "\\", "\\\\"); @@ -2504,10 +2397,8 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( directory.c_str(), directory.c_str()); bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), exc_options).Success(); - if (!syspath_retval) { - return llvm::make_error<llvm::StringError>( - "Python sys.path handling failed", llvm::inconvertibleErrorCode()); - } + if (!syspath_retval) + return llvm::createStringError("Python sys.path handling failed"); return llvm::Error::success(); }; @@ -2766,6 +2657,85 @@ bool ScriptInterpreterPythonImpl::RunScriptBasedCommand( return ret_val; } +bool ScriptInterpreterPythonImpl::RunScriptBasedParsedCommand( + StructuredData::GenericSP impl_obj_sp, Args &args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Status &error, + const lldb_private::ExecutionContext &exe_ctx) { + if (!impl_obj_sp || !impl_obj_sp->IsValid()) { + error.SetErrorString("no function to execute"); + return false; + } + + lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); + lldb::ExecutionContextRefSP exe_ctx_ref_sp(new ExecutionContextRef(exe_ctx)); + + if (!debugger_sp.get()) { + error.SetErrorString("invalid Debugger pointer"); + return false; + } + + bool ret_val = false; + + std::string err_msg; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | + (cmd_retobj.GetInteractive() ? 0 : Locker::NoSTDIN), + Locker::FreeLock | Locker::TearDownSession); + + SynchronicityHandler synch_handler(debugger_sp, synchronicity); + + StructuredData::ArraySP args_arr_sp(new StructuredData::Array()); + + for (const Args::ArgEntry &entry : args) { + args_arr_sp->AddStringItem(entry.ref()); + } + StructuredDataImpl args_impl(args_arr_sp); + + ret_val = SWIGBridge::LLDBSwigPythonCallParsedCommandObject( + static_cast<PyObject *>(impl_obj_sp->GetValue()), debugger_sp, + args_impl, cmd_retobj, exe_ctx_ref_sp); + } + + if (!ret_val) + error.SetErrorString("unable to execute script function"); + else if (cmd_retobj.GetStatus() == eReturnStatusFailed) + return false; + + error.Clear(); + return ret_val; +} + +std::optional<std::string> +ScriptInterpreterPythonImpl::GetRepeatCommandForScriptedCommand( + StructuredData::GenericSP impl_obj_sp, Args &args) { + if (!impl_obj_sp || !impl_obj_sp->IsValid()) + return std::nullopt; + + lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); + + if (!debugger_sp.get()) + return std::nullopt; + + std::optional<std::string> ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + StructuredData::ArraySP args_arr_sp(new StructuredData::Array()); + + // For scripting commands, we send the command string: + std::string command; + args.GetQuotedCommandString(command); + ret_val = SWIGBridge::LLDBSwigPythonGetRepeatCommandForScriptedCommand( + static_cast<PyObject *>(impl_obj_sp->GetValue()), command); + } + return ret_val; +} + /// In Python, a special attribute __doc__ contains the docstring for an object /// (function, method, class, ...) if any is defined Otherwise, the attribute's /// value is None. @@ -2884,6 +2854,205 @@ uint32_t ScriptInterpreterPythonImpl::GetFlagsForCommandObject( return result; } +StructuredData::ObjectSP +ScriptInterpreterPythonImpl::GetOptionsForCommandObject( + StructuredData::GenericSP cmd_obj_sp) { + StructuredData::ObjectSP result = {}; + + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_options_definition"; + + if (!cmd_obj_sp) + return result; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)cmd_obj_sp->GetValue()); + + if (!implementor.IsAllocated()) + return result; + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return result; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return result; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + PythonDictionary py_return = unwrapOrSetPythonException( + As<PythonDictionary>(implementor.CallMethod(callee_name))); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return {}; + } + return py_return.CreateStructuredObject(); +} + +StructuredData::ObjectSP +ScriptInterpreterPythonImpl::GetArgumentsForCommandObject( + StructuredData::GenericSP cmd_obj_sp) { + StructuredData::ObjectSP result = {}; + + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "get_args_definition"; + + if (!cmd_obj_sp) + return result; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)cmd_obj_sp->GetValue()); + + if (!implementor.IsAllocated()) + return result; + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return result; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return result; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + PythonList py_return = unwrapOrSetPythonException( + As<PythonList>(implementor.CallMethod(callee_name))); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return {}; + } + return py_return.CreateStructuredObject(); +} + +void +ScriptInterpreterPythonImpl::OptionParsingStartedForCommandObject( + StructuredData::GenericSP cmd_obj_sp) { + + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "option_parsing_started"; + + if (!cmd_obj_sp) + return ; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)cmd_obj_sp->GetValue()); + + if (!implementor.IsAllocated()) + return; + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + // option_parsing_starting doesn't return anything, ignore anything but + // python errors. + unwrapOrSetPythonException( + As<bool>(implementor.CallMethod(callee_name))); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return; + } +} + +bool +ScriptInterpreterPythonImpl::SetOptionValueForCommandObject( + StructuredData::GenericSP cmd_obj_sp, ExecutionContext *exe_ctx, + llvm::StringRef long_option, llvm::StringRef value) { + StructuredData::ObjectSP result = {}; + + Locker py_lock(this, Locker::AcquireLock | Locker::NoSTDIN, Locker::FreeLock); + + static char callee_name[] = "set_option_value"; + + if (!cmd_obj_sp) + return false; + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)cmd_obj_sp->GetValue()); + + if (!implementor.IsAllocated()) + return false; + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return false; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return false; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + lldb::ExecutionContextRefSP exe_ctx_ref_sp; + if (exe_ctx) + exe_ctx_ref_sp.reset(new ExecutionContextRef(exe_ctx)); + PythonObject ctx_ref_obj = SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp); + + bool py_return = unwrapOrSetPythonException( + As<bool>(implementor.CallMethod(callee_name, ctx_ref_obj, long_option.str().c_str(), + value.str().c_str()))); + + // if it fails, print the error but otherwise go on + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return false; + } + return py_return; +} + bool ScriptInterpreterPythonImpl::GetLongHelpForCommandObject( StructuredData::GenericSP cmd_obj_sp, std::string &dest) { dest.clear(); diff --git a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index a33499816d8d..c2024efb395d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/contrib/llvm-project/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -78,33 +78,8 @@ public: CreateScriptCommandObject(const char *class_name) override; StructuredData::ObjectSP - CreateScriptedThreadPlan(const char *class_name, - const StructuredDataImpl &args_data, - std::string &error_str, - lldb::ThreadPlanSP thread_plan) override; - - StructuredData::ObjectSP CreateStructuredDataFromScriptObject(ScriptObject obj) override; - bool ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp, - Event *event, - bool &script_error) override; - - bool ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp, - Event *event, bool &script_error) override; - - bool ScriptedThreadPlanIsStale(StructuredData::ObjectSP implementor_sp, - bool &script_error) override; - - lldb::StateType - ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp, - bool &script_error) override; - - bool - ScriptedThreadPlanGetStopDescription(StructuredData::ObjectSP implementor_sp, - lldb_private::Stream *s, - bool &script_error) override; - StructuredData::GenericSP CreateScriptedBreakpointResolver(const char *class_name, const StructuredDataImpl &args_data, @@ -136,6 +111,9 @@ public: lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; + lldb::ScriptedThreadPlanInterfaceSP + CreateScriptedThreadPlanInterface() override; + lldb::OperatingSystemInterfaceSP CreateOperatingSystemInterface() override; StructuredData::ObjectSP @@ -182,6 +160,16 @@ public: lldb_private::CommandReturnObject &cmd_retobj, Status &error, const lldb_private::ExecutionContext &exe_ctx) override; + bool RunScriptBasedParsedCommand( + StructuredData::GenericSP impl_obj_sp, Args &args, + ScriptedCommandSynchronicity synchronicity, + lldb_private::CommandReturnObject &cmd_retobj, Status &error, + const lldb_private::ExecutionContext &exe_ctx) override; + + std::optional<std::string> + GetRepeatCommandForScriptedCommand(StructuredData::GenericSP impl_obj_sp, + Args &args) override; + Status GenerateFunction(const char *signature, const StringList &input, bool is_callback) override; @@ -212,6 +200,20 @@ public: bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp, std::string &dest) override; + + StructuredData::ObjectSP + GetOptionsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override; + + StructuredData::ObjectSP + GetArgumentsForCommandObject(StructuredData::GenericSP cmd_obj_sp) override; + + bool SetOptionValueForCommandObject(StructuredData::GenericSP cmd_obj_sp, + ExecutionContext *exe_ctx, + llvm::StringRef long_option, + llvm::StringRef value) override; + + void OptionParsingStartedForCommandObject( + StructuredData::GenericSP cmd_obj_sp) override; bool CheckObjectExists(const char *name) override { if (!name || !name[0]) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index b1f7397d6b0f..3977dc3a6d67 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -918,7 +918,7 @@ void SymbolFileBreakpad::ParseUnwindData() { m_unwind_data->win.Sort(); } -uint64_t SymbolFileBreakpad::GetDebugInfoSize() { +uint64_t SymbolFileBreakpad::GetDebugInfoSize(bool load_all_debug_info) { // Breakpad files are all debug info. return m_objfile_sp->GetByteSize(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h index 41e4e3b25801..041b388f9f34 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -120,9 +120,8 @@ public: llvm::Expected<lldb::TypeSystemSP> GetTypeSystemForLanguage(lldb::LanguageType language) override { - return llvm::make_error<llvm::StringError>( - "SymbolFileBreakpad does not support GetTypeSystemForLanguage", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "SymbolFileBreakpad does not support GetTypeSystemForLanguage"); } CompilerDeclContext FindNamespace(ConstString name, @@ -141,7 +140,7 @@ public: llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } - uint64_t GetDebugInfoSize() override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; private: // A class representing a position in the breakpad file. Useful for diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp index 65f5b1a5f1b0..386ba44c5ea6 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/CTF/SymbolFileCTF.cpp @@ -342,7 +342,7 @@ SymbolFileCTF::CreateInteger(const CTFInteger &ctf_integer) { CompilerType compiler_type = m_ast->GetBasicType(basic_type); - if (basic_type != eBasicTypeVoid) { + if (basic_type != eBasicTypeVoid && basic_type != eBasicTypeBool) { // Make sure the type we got is an integer type. bool compiler_type_is_signed = false; if (!compiler_type.IsIntegerType(compiler_type_is_signed)) @@ -802,7 +802,8 @@ size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) { } Type *arg_type = ResolveTypeUID(arg_uid); - arg_types.push_back(arg_type->GetFullCompilerType()); + arg_types.push_back(arg_type ? arg_type->GetFullCompilerType() + : CompilerType()); } if (symbol) { @@ -813,8 +814,9 @@ size_t SymbolFileCTF::ParseFunctions(CompileUnit &cu) { // Create function type. CompilerType func_type = m_ast->CreateFunctionType( - ret_type->GetFullCompilerType(), arg_types.data(), arg_types.size(), - is_variadic, 0, clang::CallingConv::CC_C); + ret_type ? ret_type->GetFullCompilerType() : CompilerType(), + arg_types.data(), arg_types.size(), is_variadic, 0, + clang::CallingConv::CC_C); lldb::user_id_t function_type_uid = m_types.size() + 1; TypeSP type_sp = MakeType(function_type_uid, symbol->GetName(), 0, nullptr, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp index 33537df4f507..1703597a7cd2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -284,8 +284,12 @@ void AppleDWARFIndex::GetFunctions( for (const auto &entry : m_apple_names_up->equal_range(name)) { DIERef die_ref(std::nullopt, DIERef::Section::DebugInfo, *entry.getDIESectionOffset()); - if (!ProcessFunctionDIE(lookup_info, die_ref, dwarf, parent_decl_ctx, - callback)) + DWARFDIE die = dwarf.GetDIE(die_ref); + if (!die) { + ReportInvalidDIERef(die_ref, name); + continue; + } + if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, callback)) return; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index 66db396279e0..abaeb2502cbb 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -58,7 +58,7 @@ public: virtual void EnsureAllDIEsInDeclContextHaveBeenParsed( CompilerDeclContext decl_context) = 0; - virtual ConstString GetDIEClassTemplateParams(const DWARFDIE &die) = 0; + virtual std::string GetDIEClassTemplateParams(const DWARFDIE &die) = 0; static std::optional<SymbolFile::ArrayInfo> ParseChildArrayInfo(const DWARFDIE &parent_die, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 54d06b1115a2..85c59a605c67 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -38,10 +38,12 @@ #include "lldb/Utility/StreamString.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Type.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Demangle/Demangle.h" #include <map> @@ -222,7 +224,6 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, TypePayloadClang(GetOwningClangModule(die))); - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type); if (tag_decl) { LinkDeclContextToDIE(tag_decl, die); @@ -235,20 +236,10 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, return type_sp; } -static void ForcefullyCompleteType(CompilerType type) { - bool started = TypeSystemClang::StartTagDeclarationDefinition(type); - lldbassert(started && "Unable to start a class type definition."); - TypeSystemClang::CompleteTagDeclarationDefinition(type); - const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); - auto ts_sp = type.GetTypeSystem(); - auto ts = ts_sp.dyn_cast_or_null<TypeSystemClang>(); - if (ts) - ts->SetDeclIsForcefullyCompleted(td); -} - -/// This function serves a similar purpose as RequireCompleteType above, but it -/// avoids completing the type if it is not immediately necessary. It only -/// ensures we _can_ complete the type later. +/// This function ensures we are able to add members (nested types, functions, +/// etc.) to this type. It does so by starting its definition even if one cannot +/// be found in the debug info. This means the type may need to be "forcibly +/// completed" later -- see CompleteTypeFromDWARF). static void PrepareContextToReceiveMembers(TypeSystemClang &ast, ClangASTImporter &ast_importer, clang::DeclContext *decl_ctx, @@ -258,14 +249,12 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast, if (!tag_decl_ctx) return; // Non-tag context are always ready. - // We have already completed the type, or we have found its definition and are - // ready to complete it later (cf. ParseStructureLikeDIE). + // We have already completed the type or it is already prepared. if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined()) return; - // We reach this point of the tag was present in the debug info as a - // declaration only. If it was imported from another AST context (in the - // gmodules case), we can complete the type by doing a full import. + // If this tag was imported from another AST context (in the gmodules case), + // we can complete the type by doing a full import. // If this type was not imported from an external AST, there's nothing to do. CompilerType type = ast.GetTypeForDecl(tag_decl_ctx); @@ -279,9 +268,9 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast, type_name_cstr ? type_name_cstr : "", die.GetOffset()); } - // We don't have a type definition and/or the import failed. We must - // forcefully complete the type to avoid crashes. - ForcefullyCompleteType(type); + // We don't have a type definition and/or the import failed, but we need to + // add members to it. Start the definition to make that possible. + tag_decl_ctx->startDefinition(); } ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { @@ -452,99 +441,90 @@ TypeSP DWARFASTParserClang::ParseTypeFromDWARF(const SymbolContext &sc, log, "DWARFASTParserClang::ParseTypeFromDWARF " "(die = {0:x16}, decl_ctx = {1:p} (die " - "{2:x16})) {3} name = '{4}')", + "{2:x16})) {3} ({4}) name = '{5}')", die.GetOffset(), static_cast<void *>(context), context_die.GetOffset(), - die.GetTagAsCString(), die.GetName()); + DW_TAG_value_to_name(die.Tag()), die.Tag(), die.GetName()); } - Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); - if (type_ptr == DIE_IS_BEING_PARSED) - return nullptr; - if (type_ptr) - return type_ptr->shared_from_this(); // Set a bit that lets us know that we are currently parsing this - dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + if (auto [it, inserted] = + dwarf->GetDIEToType().try_emplace(die.GetDIE(), DIE_IS_BEING_PARSED); + !inserted) { + if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED) + return nullptr; + return it->getSecond()->shared_from_this(); + } ParsedDWARFTypeAttributes attrs(die); + TypeSP type_sp; if (DWARFDIE signature_die = attrs.signature.Reference()) { - if (TypeSP type_sp = - ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr)) { - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + type_sp = ParseTypeFromDWARF(sc, signature_die, type_is_new_ptr); + if (type_sp) { if (clang::DeclContext *decl_ctx = GetCachedClangDeclContextForDIE(signature_die)) LinkDeclContextToDIE(decl_ctx, die); - return type_sp; } - return nullptr; - } - - if (type_is_new_ptr) - *type_is_new_ptr = true; - - const dw_tag_t tag = die.Tag(); - - TypeSP type_sp; - - switch (tag) { - case DW_TAG_typedef: - case DW_TAG_base_type: - case DW_TAG_pointer_type: - case DW_TAG_reference_type: - case DW_TAG_rvalue_reference_type: - case DW_TAG_const_type: - case DW_TAG_restrict_type: - case DW_TAG_volatile_type: - case DW_TAG_atomic_type: - case DW_TAG_unspecified_type: { - type_sp = ParseTypeModifier(sc, die, attrs); - break; - } - - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: { - type_sp = ParseStructureLikeDIE(sc, die, attrs); - break; - } + } else { + if (type_is_new_ptr) + *type_is_new_ptr = true; - case DW_TAG_enumeration_type: { - type_sp = ParseEnum(sc, die, attrs); - break; - } + const dw_tag_t tag = die.Tag(); - case DW_TAG_inlined_subroutine: - case DW_TAG_subprogram: - case DW_TAG_subroutine_type: { - type_sp = ParseSubroutine(die, attrs); - break; - } - case DW_TAG_array_type: { - type_sp = ParseArrayType(die, attrs); - break; - } - case DW_TAG_ptr_to_member_type: { - type_sp = ParsePointerToMemberType(die, attrs); - break; + switch (tag) { + case DW_TAG_typedef: + case DW_TAG_base_type: + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_rvalue_reference_type: + case DW_TAG_const_type: + case DW_TAG_restrict_type: + case DW_TAG_volatile_type: + case DW_TAG_LLVM_ptrauth_type: + case DW_TAG_atomic_type: + case DW_TAG_unspecified_type: + type_sp = ParseTypeModifier(sc, die, attrs); + break; + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + type_sp = ParseStructureLikeDIE(sc, die, attrs); + break; + case DW_TAG_enumeration_type: + type_sp = ParseEnum(sc, die, attrs); + break; + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: + type_sp = ParseSubroutine(die, attrs); + break; + case DW_TAG_array_type: + type_sp = ParseArrayType(die, attrs); + break; + case DW_TAG_ptr_to_member_type: + type_sp = ParsePointerToMemberType(die, attrs); + break; + default: + dwarf->GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: unhandled type tag {1:x4} ({2}), " + "please file a bug and " + "attach the file at the start of this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + break; + } + UpdateSymbolContextScopeForType(sc, die, type_sp); } - default: - dwarf->GetObjectFile()->GetModule()->ReportError( - "[{0:x16}]: unhandled type tag {1:x4} ({2}), " - "please file a bug and " - "attach the file at the start of this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - break; + if (type_sp) { + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); } - - // TODO: We should consider making the switch above exhaustive to simplify - // control flow in ParseTypeFromDWARF. Then, we could simply replace this - // return statement with a call to llvm_unreachable. - return UpdateSymbolContextScopeForType(sc, die, type_sp); + return type_sp; } static std::optional<uint32_t> ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, ModuleSP module_sp) { + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + // With DWARF 3 and later, if the value is an integer constant, // this form value is the offset in bytes from the beginning of // the containing entity. @@ -552,21 +532,56 @@ ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, return form_value.Unsigned(); Value initialValue(0); - Value memberOffset(0); const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); - if (!DWARFExpression::Evaluate( - nullptr, // ExecutionContext * - nullptr, // RegisterContext * - module_sp, DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU(), eRegisterKindDWARF, &initialValue, nullptr, memberOffset, - nullptr)) { + + llvm::Expected<Value> memberOffset = DWARFExpression::Evaluate( + /*ExecutionContext=*/nullptr, + /*RegisterContext=*/nullptr, module_sp, + DataExtractor(debug_info_data, block_offset, block_length), die.GetCU(), + eRegisterKindDWARF, &initialValue, nullptr); + if (!memberOffset) { + LLDB_LOG_ERROR(log, memberOffset.takeError(), + "ExtractDataMemberLocation failed: {0}"); return {}; } - return memberOffset.ResolveValue(nullptr).UInt(); + return memberOffset->ResolveValue(nullptr).UInt(); +} + +static TypePayloadClang GetPtrAuthMofidierPayload(const DWARFDIE &die) { + auto getAttr = [&](llvm::dwarf::Attribute Attr, unsigned defaultValue = 0) { + return die.GetAttributeValueAsUnsigned(Attr, defaultValue); + }; + const unsigned key = getAttr(DW_AT_LLVM_ptrauth_key); + const bool addr_disc = getAttr(DW_AT_LLVM_ptrauth_address_discriminated); + const unsigned extra = getAttr(DW_AT_LLVM_ptrauth_extra_discriminator); + const bool isapointer = getAttr(DW_AT_LLVM_ptrauth_isa_pointer); + const bool authenticates_null_values = + getAttr(DW_AT_LLVM_ptrauth_authenticates_null_values); + const unsigned authentication_mode_int = getAttr( + DW_AT_LLVM_ptrauth_authentication_mode, + static_cast<unsigned>(clang::PointerAuthenticationMode::SignAndAuth)); + clang::PointerAuthenticationMode authentication_mode = + clang::PointerAuthenticationMode::SignAndAuth; + if (authentication_mode_int >= + static_cast<unsigned>(clang::PointerAuthenticationMode::None) && + authentication_mode_int <= + static_cast<unsigned>( + clang::PointerAuthenticationMode::SignAndAuth)) { + authentication_mode = + static_cast<clang::PointerAuthenticationMode>(authentication_mode_int); + } else { + die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: invalid pointer authentication mode method {1:x4}", + die.GetOffset(), authentication_mode_int); + } + auto ptr_auth = clang::PointerAuthQualifier::Create( + key, addr_disc, extra, authentication_mode, isapointer, + authenticates_null_values); + return TypePayloadClang(ptr_auth.getAsOpaqueValue()); } lldb::TypeSP @@ -579,6 +594,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU()); Type::ResolveState resolve_state = Type::ResolveState::Unresolved; Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + TypePayloadClang payload(GetOwningClangModule(die)); TypeSP type_sp; CompilerType clang_type; @@ -676,6 +692,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, case DW_TAG_volatile_type: encoding_data_type = Type::eEncodingIsVolatileUID; break; + case DW_TAG_LLVM_ptrauth_type: + encoding_data_type = Type::eEncodingIsLLVMPtrAuthUID; + payload = GetPtrAuthMofidierPayload(die); + break; case DW_TAG_atomic_type: encoding_data_type = Type::eEncodingIsAtomicUID; break; @@ -726,9 +746,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = {0:x16}) {1} '{2}' " + "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' " "is Objective-C 'id' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); @@ -737,9 +758,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = {0:x16}) {1} '{2}' " + "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' " "is Objective-C 'Class' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCClass); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); @@ -748,9 +770,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = {0:x16}) {1} '{2}' " + "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' " "is Objective-C 'selector' built-in type.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCSel); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); @@ -769,10 +792,10 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, if (log) dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ParseType (die = {0:x16}) {1} " - "'{2}' is 'objc_object*', which we overrode to " - "'id'.", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + "SymbolFileDWARF::ParseType (die = {0:x16}) {1} ({2}) '{3}' " + "is 'objc_object*', which we overrode to 'id'.", + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); clang_type = m_ast.GetBasicType(eBasicTypeObjCID); encoding_data_type = Type::eEncodingIsUID; attrs.type.Clear(); @@ -783,121 +806,142 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, } } - type_sp = dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr, - attrs.type.Reference().GetID(), encoding_data_type, - &attrs.decl, clang_type, resolve_state, - TypePayloadClang(GetOwningClangModule(die))); - - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - return type_sp; + return dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr, + attrs.type.Reference().GetID(), encoding_data_type, + &attrs.decl, clang_type, resolve_state, payload); } -ConstString +std::string DWARFASTParserClang::GetDIEClassTemplateParams(const DWARFDIE &die) { if (llvm::StringRef(die.GetName()).contains("<")) - return ConstString(); + return {}; TypeSystemClang::TemplateParameterInfos template_param_infos; - if (ParseTemplateParameterInfos(die, template_param_infos)) { - return ConstString(m_ast.PrintTemplateParams(template_param_infos)); + if (ParseTemplateParameterInfos(die, template_param_infos)) + return m_ast.PrintTemplateParams(template_param_infos); + + return {}; +} + +void DWARFASTParserClang::MapDeclDIEToDefDIE( + const lldb_private::plugin::dwarf::DWARFDIE &decl_die, + const lldb_private::plugin::dwarf::DWARFDIE &def_die) { + LinkDeclContextToDIE(GetCachedClangDeclContextForDIE(decl_die), def_die); + SymbolFileDWARF *dwarf = def_die.GetDWARF(); + ParsedDWARFTypeAttributes decl_attrs(decl_die); + ParsedDWARFTypeAttributes def_attrs(def_die); + ConstString unique_typename(decl_attrs.name); + Declaration decl_declaration(decl_attrs.decl); + GetUniqueTypeNameAndDeclaration( + decl_die, SymbolFileDWARF::GetLanguage(*decl_die.GetCU()), + unique_typename, decl_declaration); + if (UniqueDWARFASTType *unique_ast_entry_type = + dwarf->GetUniqueDWARFASTTypeMap().Find( + unique_typename, decl_die, decl_declaration, + decl_attrs.byte_size.value_or(0), + decl_attrs.is_forward_declaration)) { + unique_ast_entry_type->UpdateToDefDIE(def_die, def_attrs.decl, + def_attrs.byte_size.value_or(0)); + } else if (Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups)) { + const dw_tag_t tag = decl_die.Tag(); + LLDB_LOG(log, + "Failed to find {0:x16} {1} ({2}) type \"{3}\" in " + "UniqueDWARFASTTypeMap", + decl_die.GetID(), DW_TAG_value_to_name(tag), tag, unique_typename); } - return ConstString(); } TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, - const DWARFDIE &die, + const DWARFDIE &decl_die, ParsedDWARFTypeAttributes &attrs) { Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); - SymbolFileDWARF *dwarf = die.GetDWARF(); - const dw_tag_t tag = die.Tag(); - TypeSP type_sp; + SymbolFileDWARF *dwarf = decl_die.GetDWARF(); + const dw_tag_t tag = decl_die.Tag(); + DWARFDIE def_die; if (attrs.is_forward_declaration) { - type_sp = ParseTypeFromClangModule(sc, die, log); - if (type_sp) + if (TypeSP type_sp = ParseTypeFromClangModule(sc, decl_die, log)) return type_sp; - type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die); + def_die = dwarf->FindDefinitionDIE(decl_die); - if (!type_sp) { + if (!def_die) { SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); if (debug_map_symfile) { // We weren't able to find a full declaration in this DWARF, // see if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext(die); + def_die = debug_map_symfile->FindDefinitionDIE(decl_die); } } - if (type_sp) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF({0:p}) - {1:x16}}: {2} type \"{3}\" is a " - "forward declaration, complete type is {4:x8}", - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } - - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this - // die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); - return type_sp; - } + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF({0:p}) - {1:x16}}: {2} ({3}) type \"{4}\" is a " + "forward declaration, complete DIE is {5}", + static_cast<void *>(this), decl_die.GetID(), DW_TAG_value_to_name(tag), + tag, attrs.name.GetCString(), + def_die ? llvm::utohexstr(def_die.GetID()) : "not found"); + } + } + if (def_die) { + if (auto [it, inserted] = dwarf->GetDIEToType().try_emplace( + def_die.GetDIE(), DIE_IS_BEING_PARSED); + !inserted) { + if (it->getSecond() == nullptr || it->getSecond() == DIE_IS_BEING_PARSED) + return nullptr; + return it->getSecond()->shared_from_this(); + } + attrs = ParsedDWARFTypeAttributes(def_die); + } else { + // No definition found. Proceed with the declaration die. We can use it to + // create a forward-declared type. + def_die = decl_die; } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), - DW_TAG_value_to_name(tag), type_name_cstr); CompilerType enumerator_clang_type; - CompilerType clang_type; - clang_type = CompilerType( - m_ast.weak_from_this(), - dwarf->GetForwardDeclDIEToCompilerType().lookup(die.GetDIE())); - if (!clang_type) { - if (attrs.type.IsValid()) { - Type *enumerator_type = - dwarf->ResolveTypeUID(attrs.type.Reference(), true); - if (enumerator_type) - enumerator_clang_type = enumerator_type->GetFullCompilerType(); - } + if (attrs.type.IsValid()) { + Type *enumerator_type = + dwarf->ResolveTypeUID(attrs.type.Reference(), true); + if (enumerator_type) + enumerator_clang_type = enumerator_type->GetFullCompilerType(); + } - if (!enumerator_clang_type) { - if (attrs.byte_size) { - enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - "", DW_ATE_signed, *attrs.byte_size * 8); - } else { - enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); - } + if (!enumerator_clang_type) { + if (attrs.byte_size) { + enumerator_clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( + "", DW_ATE_signed, *attrs.byte_size * 8); + } else { + enumerator_clang_type = m_ast.GetBasicType(eBasicTypeInt); } - - clang_type = m_ast.CreateEnumerationType( - attrs.name.GetStringRef(), - GetClangDeclContextContainingDIE(die, nullptr), - GetOwningClangModule(die), attrs.decl, enumerator_clang_type, - attrs.is_scoped_enum); - } else { - enumerator_clang_type = m_ast.GetEnumerationIntegerType(clang_type); } - LinkDeclContextToDIE(TypeSystemClang::GetDeclContextForType(clang_type), die); - - type_sp = - dwarf->MakeType(die.GetID(), attrs.name, attrs.byte_size, nullptr, + CompilerType clang_type = m_ast.CreateEnumerationType( + attrs.name.GetStringRef(), GetClangDeclContextContainingDIE(def_die, nullptr), + GetOwningClangModule(def_die), attrs.decl, enumerator_clang_type, + attrs.is_scoped_enum); + TypeSP type_sp = + dwarf->MakeType(def_die.GetID(), attrs.name, attrs.byte_size, nullptr, attrs.type.Reference().GetID(), Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Forward, - TypePayloadClang(GetOwningClangModule(die))); + TypePayloadClang(GetOwningClangModule(def_die))); + + clang::DeclContext *type_decl_ctx = + TypeSystemClang::GetDeclContextForType(clang_type); + LinkDeclContextToDIE(type_decl_ctx, decl_die); + if (decl_die != def_die) { + LinkDeclContextToDIE(type_decl_ctx, def_die); + dwarf->GetDIEToType()[def_die.GetDIE()] = type_sp.get(); + // Declaration DIE is inserted into the type map in ParseTypeFromDWARF + } + if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { - if (die.HasChildren()) { + if (def_die.HasChildren()) { bool is_signed = false; enumerator_clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, - type_sp->GetByteSize(nullptr).value_or(0), die); + type_sp->GetByteSize(nullptr).value_or(0), def_die); } TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } else { @@ -905,7 +949,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, "DWARF DIE at {0:x16} named \"{1}\" was not able to start its " "definition.\nPlease file a bug and attach the file at the " "start of this error message", - die.GetOffset(), attrs.name.GetCString()); + def_die.GetOffset(), attrs.name.GetCString()); } return type_sp; } @@ -940,6 +984,184 @@ ConvertDWARFCallingConventionToClang(const ParsedDWARFTypeAttributes &attrs) { return clang::CC_C; } +bool DWARFASTParserClang::ParseObjCMethod( + const ObjCLanguage::MethodName &objc_method, const DWARFDIE &die, + CompilerType clang_type, const ParsedDWARFTypeAttributes &attrs, + bool is_variadic) { + SymbolFileDWARF *dwarf = die.GetDWARF(); + assert(dwarf); + + const auto tag = die.Tag(); + ConstString class_name(objc_method.GetClassName()); + if (!class_name) + return false; + + TypeSP complete_objc_class_type_sp = + dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), class_name, + false); + + if (!complete_objc_class_type_sp) + return false; + + CompilerType type_clang_forward_type = + complete_objc_class_type_sp->GetForwardCompilerType(); + + if (!type_clang_forward_type) + return false; + + if (!TypeSystemClang::IsObjCObjectOrInterfaceType(type_clang_forward_type)) + return false; + + clang::ObjCMethodDecl *objc_method_decl = m_ast.AddMethodToObjCObjectType( + type_clang_forward_type, attrs.name.GetCString(), clang_type, + attrs.is_artificial, is_variadic, attrs.is_objc_direct_call); + + if (!objc_method_decl) { + dwarf->GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: invalid Objective-C method {1:x4} ({2}), " + "please file a bug and attach the file at the start of " + "this error message", + die.GetOffset(), tag, DW_TAG_value_to_name(tag)); + return false; + } + + LinkDeclContextToDIE(objc_method_decl, die); + m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); + + return true; +} + +std::pair<bool, TypeSP> DWARFASTParserClang::ParseCXXMethod( + const DWARFDIE &die, CompilerType clang_type, + const ParsedDWARFTypeAttributes &attrs, const DWARFDIE &decl_ctx_die, + bool is_static, bool &ignore_containing_context) { + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + SymbolFileDWARF *dwarf = die.GetDWARF(); + assert(dwarf); + + Type *class_type = dwarf->ResolveType(decl_ctx_die); + if (!class_type) + return {}; + + if (class_type->GetID() != decl_ctx_die.GetID() || + IsClangModuleFwdDecl(decl_ctx_die)) { + + // We uniqued the parent class of this function to another + // class so we now need to associate all dies under + // "decl_ctx_die" to DIEs in the DIE for "class_type"... + if (DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID())) { + std::vector<DWARFDIE> failures; + + CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, class_type, + failures); + + // FIXME do something with these failures that's + // smarter than just dropping them on the ground. + // Unfortunately classes don't like having stuff added + // to them after their definitions are complete... + + Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); + if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) + return {true, type_ptr->shared_from_this()}; + } + } + + if (attrs.specification.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the specification has a valid clang decl context. + class_type->GetForwardCompilerType(); + // If we have a specification, then the function type should + // have been made with the specification and not with this + // die. + DWARFDIE spec_die = attrs.specification.Reference(); + clang::DeclContext *spec_clang_decl_ctx = + GetClangDeclContextForDIE(spec_die); + if (spec_clang_decl_ctx) + LinkDeclContextToDIE(spec_clang_decl_ctx, die); + else + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "{0:x8}: DW_AT_specification({1:x16}" + ") has no decl\n", + die.GetID(), spec_die.GetOffset()); + + return {true, nullptr}; + } + + if (attrs.abstract_origin.IsValid()) { + // We have a specification which we are going to base our + // function prototype off of, so we need this type to be + // completed so that the m_die_to_decl_ctx for the method in + // the abstract origin has a valid clang decl context. + class_type->GetForwardCompilerType(); + + DWARFDIE abs_die = attrs.abstract_origin.Reference(); + clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE(abs_die); + if (abs_clang_decl_ctx) + LinkDeclContextToDIE(abs_clang_decl_ctx, die); + else + dwarf->GetObjectFile()->GetModule()->ReportWarning( + "{0:x8}: DW_AT_abstract_origin({1:x16}" + ") has no decl\n", + die.GetID(), abs_die.GetOffset()); + + return {true, nullptr}; + } + + CompilerType class_opaque_type = class_type->GetForwardCompilerType(); + if (!TypeSystemClang::IsCXXClassType(class_opaque_type)) + return {}; + + PrepareContextToReceiveMembers( + m_ast, GetClangASTImporter(), + TypeSystemClang::GetDeclContextForType(class_opaque_type), die, + attrs.name.GetCString()); + + // We have a C++ member function with no children (this pointer!) and clang + // will get mad if we try and make a function that isn't well formed in the + // DWARF, so we will just skip it... + if (!is_static && !die.HasChildren()) + return {true, nullptr}; + + const bool is_attr_used = false; + // Neither GCC 4.2 nor clang++ currently set a valid + // accessibility in the DWARF for C++ methods... + // Default to public for now... + const auto accessibility = + attrs.accessibility == eAccessNone ? eAccessPublic : attrs.accessibility; + + clang::CXXMethodDecl *cxx_method_decl = m_ast.AddMethodToCXXRecordType( + class_opaque_type.GetOpaqueQualType(), attrs.name.GetCString(), + attrs.mangled_name, clang_type, accessibility, attrs.is_virtual, + is_static, attrs.is_inline, attrs.is_explicit, is_attr_used, + attrs.is_artificial); + + if (cxx_method_decl) { + LinkDeclContextToDIE(cxx_method_decl, die); + + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + + char const *object_pointer_name = + attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr; + if (object_pointer_name) { + metadata.SetObjectPtrName(object_pointer_name); + LLDB_LOGF(log, "Setting object pointer name: %s on method object %p.\n", + object_pointer_name, static_cast<void *>(cxx_method_decl)); + } + m_ast.SetMetadata(cxx_method_decl, metadata); + } else { + ignore_containing_context = true; + } + + // Artificial methods are always handled even when we + // don't create a new declaration for them. + const bool type_handled = cxx_method_decl != nullptr || attrs.is_artificial; + + return {type_handled, nullptr}; +} + TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs) { @@ -954,13 +1176,6 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, unsigned type_quals = 0; - std::string object_pointer_name; - if (attrs.object_pointer) { - const char *object_pointer_name_cstr = attrs.object_pointer.GetName(); - if (object_pointer_name_cstr) - object_pointer_name = object_pointer_name_cstr; - } - DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), DW_TAG_value_to_name(tag), type_name_cstr); @@ -1031,208 +1246,19 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, if (attrs.name) { bool type_handled = false; if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { - std::optional<const ObjCLanguage::MethodName> objc_method = - ObjCLanguage::MethodName::Create(attrs.name.GetStringRef(), true); - if (objc_method) { - CompilerType class_opaque_type; - ConstString class_name(objc_method->GetClassName()); - if (class_name) { - TypeSP complete_objc_class_type_sp( - dwarf->FindCompleteObjCDefinitionTypeForDIE(DWARFDIE(), - class_name, false)); - - if (complete_objc_class_type_sp) { - CompilerType type_clang_forward_type = - complete_objc_class_type_sp->GetForwardCompilerType(); - if (TypeSystemClang::IsObjCObjectOrInterfaceType( - type_clang_forward_type)) - class_opaque_type = type_clang_forward_type; - } - } - - if (class_opaque_type) { - clang::ObjCMethodDecl *objc_method_decl = - m_ast.AddMethodToObjCObjectType( - class_opaque_type, attrs.name.GetCString(), clang_type, - attrs.is_artificial, is_variadic, attrs.is_objc_direct_call); - type_handled = objc_method_decl != nullptr; - if (type_handled) { - LinkDeclContextToDIE(objc_method_decl, die); - m_ast.SetMetadataAsUserID(objc_method_decl, die.GetID()); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - "[{0:x16}]: invalid Objective-C method {1:x4} ({2}), " - "please file a bug and attach the file at the start of " - "this error message", - die.GetOffset(), tag, DW_TAG_value_to_name(tag)); - } - } + if (std::optional<const ObjCLanguage::MethodName> objc_method = + ObjCLanguage::MethodName::Create(attrs.name.GetStringRef(), + true)) { + type_handled = + ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic); } else if (is_cxx_method) { - // Look at the parent of this DIE and see if it is a class or - // struct and see if this is actually a C++ method - Type *class_type = dwarf->ResolveType(decl_ctx_die); - if (class_type) { - if (class_type->GetID() != decl_ctx_die.GetID() || - IsClangModuleFwdDecl(decl_ctx_die)) { - - // We uniqued the parent class of this function to another - // class so we now need to associate all dies under - // "decl_ctx_die" to DIEs in the DIE for "class_type"... - DWARFDIE class_type_die = dwarf->GetDIE(class_type->GetID()); - - if (class_type_die) { - std::vector<DWARFDIE> failures; - - CopyUniqueClassMethodTypes(decl_ctx_die, class_type_die, - class_type, failures); - - // FIXME do something with these failures that's - // smarter than just dropping them on the ground. - // Unfortunately classes don't like having stuff added - // to them after their definitions are complete... - - Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - return type_ptr->shared_from_this(); - } - } - } + auto [handled, type_sp] = + ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static, + ignore_containing_context); + if (type_sp) + return type_sp; - if (attrs.specification.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the specification has a valid clang decl context. - class_type->GetForwardCompilerType(); - // If we have a specification, then the function type should - // have been made with the specification and not with this - // die. - DWARFDIE spec_die = attrs.specification.Reference(); - clang::DeclContext *spec_clang_decl_ctx = - GetClangDeclContextForDIE(spec_die); - if (spec_clang_decl_ctx) { - LinkDeclContextToDIE(spec_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "{0:x8}: DW_AT_specification({1:x16}" - ") has no decl\n", - die.GetID(), spec_die.GetOffset()); - } - type_handled = true; - } else if (attrs.abstract_origin.IsValid()) { - // We have a specification which we are going to base our - // function prototype off of, so we need this type to be - // completed so that the m_die_to_decl_ctx for the method in - // the abstract origin has a valid clang decl context. - class_type->GetForwardCompilerType(); - - DWARFDIE abs_die = attrs.abstract_origin.Reference(); - clang::DeclContext *abs_clang_decl_ctx = - GetClangDeclContextForDIE(abs_die); - if (abs_clang_decl_ctx) { - LinkDeclContextToDIE(abs_clang_decl_ctx, die); - } else { - dwarf->GetObjectFile()->GetModule()->ReportWarning( - "{0:x8}: DW_AT_abstract_origin({1:x16}" - ") has no decl\n", - die.GetID(), abs_die.GetOffset()); - } - type_handled = true; - } else { - CompilerType class_opaque_type = - class_type->GetForwardCompilerType(); - if (TypeSystemClang::IsCXXClassType(class_opaque_type)) { - if (class_opaque_type.IsBeingDefined()) { - if (!is_static && !die.HasChildren()) { - // We have a C++ member function with no children (this - // pointer!) and clang will get mad if we try and make - // a function that isn't well formed in the DWARF, so - // we will just skip it... - type_handled = true; - } else { - llvm::PrettyStackTraceFormat stack_trace( - "SymbolFileDWARF::ParseType() is adding a method " - "%s to class %s in DIE 0x%8.8" PRIx64 " from %s", - attrs.name.GetCString(), - class_type->GetName().GetCString(), die.GetID(), - dwarf->GetObjectFile()->GetFileSpec().GetPath().c_str()); - - const bool is_attr_used = false; - // Neither GCC 4.2 nor clang++ currently set a valid - // accessibility in the DWARF for C++ methods... - // Default to public for now... - const auto accessibility = attrs.accessibility == eAccessNone - ? eAccessPublic - : attrs.accessibility; - - clang::CXXMethodDecl *cxx_method_decl = - m_ast.AddMethodToCXXRecordType( - class_opaque_type.GetOpaqueQualType(), - attrs.name.GetCString(), attrs.mangled_name, - clang_type, accessibility, attrs.is_virtual, - is_static, attrs.is_inline, attrs.is_explicit, - is_attr_used, attrs.is_artificial); - - type_handled = cxx_method_decl != nullptr; - // Artificial methods are always handled even when we - // don't create a new declaration for them. - type_handled |= attrs.is_artificial; - - if (cxx_method_decl) { - LinkDeclContextToDIE(cxx_method_decl, die); - - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); - LLDB_LOGF(log, - "Setting object pointer name: %s on method " - "object %p.\n", - object_pointer_name.c_str(), - static_cast<void *>(cxx_method_decl)); - } - m_ast.SetMetadata(cxx_method_decl, metadata); - } else { - ignore_containing_context = true; - } - } - } else { - // We were asked to parse the type for a method in a - // class, yet the class hasn't been asked to complete - // itself through the clang::ExternalASTSource protocol, - // so we need to just have the class complete itself and - // do things the right way, then our - // DIE should then have an entry in the - // dwarf->GetDIEToType() map. First - // we need to modify the dwarf->GetDIEToType() so it - // doesn't think we are trying to parse this DIE - // anymore... - dwarf->GetDIEToType()[die.GetDIE()] = NULL; - - // Now we get the full type to force our class type to - // complete itself using the clang::ExternalASTSource - // protocol which will parse all base classes and all - // methods (including the method for this DIE). - class_type->GetFullCompilerType(); - - // The type for this DIE should have been filled in the - // function call above. - Type *type_ptr = dwarf->GetDIEToType()[die.GetDIE()]; - if (type_ptr && type_ptr != DIE_IS_BEING_PARSED) { - return type_ptr->shared_from_this(); - } - - // The previous comment isn't actually true if the class wasn't - // resolved using the current method's parent DIE as source - // data. We need to ensure that we look up the method correctly - // in the class and then link the method's DIE to the unique - // CXXMethodDecl appropriately. - type_handled = true; - } - } - } - } + type_handled = handled; } } @@ -1321,13 +1347,14 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, ClangASTMetadata metadata; metadata.SetUserID(die.GetID()); - if (!object_pointer_name.empty()) { - metadata.SetObjectPtrName(object_pointer_name.c_str()); + char const *object_pointer_name = + attrs.object_pointer ? attrs.object_pointer.GetName() : nullptr; + if (object_pointer_name) { + metadata.SetObjectPtrName(object_pointer_name); LLDB_LOGF(log, "Setting object pointer name: %s on function " "object %p.", - object_pointer_name.c_str(), - static_cast<void *>(function_decl)); + object_pointer_name, static_cast<void *>(function_decl)); } m_ast.SetMetadata(function_decl, metadata); } @@ -1525,7 +1552,6 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( if (!type_sp) return type_sp; - SymbolFileDWARF *dwarf = die.GetDWARF(); DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die); dw_tag_t sc_parent_tag = sc_parent_die.Tag(); @@ -1544,18 +1570,20 @@ TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( if (symbol_context_scope != nullptr) type_sp->SetSymbolContextScope(symbol_context_scope); - - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; } -std::string -DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { - if (!die.IsValid()) - return ""; - const char *name = die.GetName(); - if (!name) - return ""; +void DWARFASTParserClang::GetUniqueTypeNameAndDeclaration( + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb::LanguageType language, lldb_private::ConstString &unique_typename, + lldb_private::Declaration &decl_declaration) { + // For C++, we rely solely upon the one definition rule that says + // only one thing can exist at a given decl context. We ignore the + // file and line that things are declared on. + if (!die.IsValid() || !Language::LanguageIsCPlusPlus(language) || + unique_typename.IsEmpty()) + return; + decl_declaration.Clear(); std::string qualified_name; DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); // TODO: change this to get the correct decl context parent.... @@ -1581,7 +1609,7 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { case DW_TAG_union_type: { if (const char *class_union_struct_name = parent_decl_ctx_die.GetName()) { qualified_name.insert( - 0, GetDIEClassTemplateParams(parent_decl_ctx_die).AsCString("")); + 0, GetDIEClassTemplateParams(parent_decl_ctx_die)); qualified_name.insert(0, "::"); qualified_name.insert(0, class_union_struct_name); } @@ -1598,51 +1626,65 @@ DWARFASTParserClang::GetCPlusPlusQualifiedName(const DWARFDIE &die) { if (qualified_name.empty()) qualified_name.append("::"); - qualified_name.append(name); - qualified_name.append(GetDIEClassTemplateParams(die).AsCString("")); + qualified_name.append(unique_typename.GetCString()); + qualified_name.append(GetDIEClassTemplateParams(die)); - return qualified_name; + unique_typename = ConstString(qualified_name); } TypeSP DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, const DWARFDIE &die, ParsedDWARFTypeAttributes &attrs) { - TypeSP type_sp; CompilerType clang_type; const dw_tag_t tag = die.Tag(); SymbolFileDWARF *dwarf = die.GetDWARF(); LanguageType cu_language = SymbolFileDWARF::GetLanguage(*die.GetCU()); Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); - // UniqueDWARFASTType is large, so don't create a local variables on the - // stack, put it on the heap. This function is often called recursively and - // clang isn't good at sharing the stack space for variables in different - // blocks. - auto unique_ast_entry_up = std::make_unique<UniqueDWARFASTType>(); - ConstString unique_typename(attrs.name); Declaration unique_decl(attrs.decl); + uint64_t byte_size = attrs.byte_size.value_or(0); + if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name && + !die.HasChildren() && cu_language == eLanguageTypeObjC) { + // Work around an issue with clang at the moment where forward + // declarations for objective C classes are emitted as: + // DW_TAG_structure_type [2] + // DW_AT_name( "ForwardObjcClass" ) + // DW_AT_byte_size( 0x00 ) + // DW_AT_decl_file( "..." ) + // DW_AT_decl_line( 1 ) + // + // Note that there is no DW_AT_declaration and there are no children, + // and the byte size is zero. + attrs.is_forward_declaration = true; + } if (attrs.name) { - if (Language::LanguageIsCPlusPlus(cu_language)) { - // For C++, we rely solely upon the one definition rule that says - // only one thing can exist at a given decl context. We ignore the - // file and line that things are declared on. - std::string qualified_name = GetCPlusPlusQualifiedName(die); - if (!qualified_name.empty()) - unique_typename = ConstString(qualified_name); - unique_decl.Clear(); - } - - if (dwarf->GetUniqueDWARFASTTypeMap().Find( - unique_typename, die, unique_decl, attrs.byte_size.value_or(-1), - *unique_ast_entry_up)) { - type_sp = unique_ast_entry_up->m_type_sp; - if (type_sp) { + GetUniqueTypeNameAndDeclaration(die, cu_language, unique_typename, + unique_decl); + if (UniqueDWARFASTType *unique_ast_entry_type = + dwarf->GetUniqueDWARFASTTypeMap().Find( + unique_typename, die, unique_decl, byte_size, + attrs.is_forward_declaration)) { + if (TypeSP type_sp = unique_ast_entry_type->m_type_sp) { dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); LinkDeclContextToDIE( - GetCachedClangDeclContextForDIE(unique_ast_entry_up->m_die), die); + GetCachedClangDeclContextForDIE(unique_ast_entry_type->m_die), die); + // If the DIE being parsed in this function is a definition and the + // entry in the map is a declaration, then we need to update the entry + // to point to the definition DIE. + if (!attrs.is_forward_declaration && + unique_ast_entry_type->m_is_forward_declaration) { + unique_ast_entry_type->UpdateToDefDIE(die, unique_decl, byte_size); + clang_type = type_sp->GetForwardCompilerType(); + + CompilerType compiler_type_no_qualifiers = + ClangUtil::RemoveFastQualifiers(clang_type); + dwarf->GetForwardDeclCompilerTypeToDIE().insert_or_assign( + compiler_type_no_qualifiers.GetOpaqueQualType(), + *die.GetDIERef()); + } return type_sp; } } @@ -1664,96 +1706,25 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, default_accessibility = eAccessPrivate; } - if (attrs.byte_size && *attrs.byte_size == 0 && attrs.name && - !die.HasChildren() && cu_language == eLanguageTypeObjC) { - // Work around an issue with clang at the moment where forward - // declarations for objective C classes are emitted as: - // DW_TAG_structure_type [2] - // DW_AT_name( "ForwardObjcClass" ) - // DW_AT_byte_size( 0x00 ) - // DW_AT_decl_file( "..." ) - // DW_AT_decl_line( 1 ) - // - // Note that there is no DW_AT_declaration and there are no children, - // and the byte size is zero. - attrs.is_forward_declaration = true; - } - - if (attrs.class_language == eLanguageTypeObjC || - attrs.class_language == eLanguageTypeObjC_plus_plus) { - if (!attrs.is_complete_objc_class && - die.Supports_DW_AT_APPLE_objc_complete_type()) { - // We have a valid eSymbolTypeObjCClass class symbol whose name - // matches the current objective C class that we are trying to find - // and this DIE isn't the complete definition (we checked - // is_complete_objc_class above and know it is false), so the real - // definition is in here somewhere - type_sp = - dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true); - - if (!type_sp) { - SymbolFileDWARFDebugMap *debug_map_symfile = - dwarf->GetDebugMapSymfile(); - if (debug_map_symfile) { - // We weren't able to find a full declaration in this DWARF, - // see if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( - die, attrs.name, true); - } - } - - if (type_sp) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF({0:p}) - {1:x16}: {2} type " - "\"{3}\" is an " - "incomplete objc type, complete type is {4:x8}", - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); - } - - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this - // die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - return type_sp; - } - } - } - - if (attrs.is_forward_declaration) { - // We have a forward declaration to a type and we need to try and - // find a full declaration. We look in the current type index just in - // case we have a forward declaration followed by an actual - // declarations in the DWARF. If this fails, we need to look - // elsewhere... - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" is a " - "forward declaration, trying to find complete type", - static_cast<void *>(this), die.GetOffset(), DW_TAG_value_to_name(tag), - attrs.name.GetCString()); - } - - // See if the type comes from a Clang module and if so, track down - // that type. - type_sp = ParseTypeFromClangModule(sc, die, log); - if (type_sp) - return type_sp; - - // type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, - // type_name_const_str); - type_sp = dwarf->FindDefinitionTypeForDWARFDeclContext(die); + if ((attrs.class_language == eLanguageTypeObjC || + attrs.class_language == eLanguageTypeObjC_plus_plus) && + !attrs.is_complete_objc_class && + die.Supports_DW_AT_APPLE_objc_complete_type()) { + // We have a valid eSymbolTypeObjCClass class symbol whose name + // matches the current objective C class that we are trying to find + // and this DIE isn't the complete definition (we checked + // is_complete_objc_class above and know it is false), so the real + // definition is in here somewhere + TypeSP type_sp = + dwarf->FindCompleteObjCDefinitionTypeForDIE(die, attrs.name, true); if (!type_sp) { SymbolFileDWARFDebugMap *debug_map_symfile = dwarf->GetDebugMapSymfile(); if (debug_map_symfile) { - // We weren't able to find a full declaration in this DWARF, see - // if we have a declaration anywhere else... - type_sp = debug_map_symfile->FindDefinitionTypeForDWARFDeclContext(die); + // We weren't able to find a full declaration in this DWARF, + // see if we have a declaration anywhere else... + type_sp = debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE( + die, attrs.name, true); } } @@ -1761,177 +1732,124 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" is a " - "forward declaration, complete type is {4:x8}", - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString(), - type_sp->GetID()); + "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" is an " + "incomplete objc type, complete type is {5:x8}", + static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), + tag, attrs.name.GetCString(), type_sp->GetID()); } - - // We found a real definition for this type elsewhere so lets use - // it and cache the fact that we found a complete type for this die - dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); - clang::DeclContext *defn_decl_ctx = - GetCachedClangDeclContextForDIE(dwarf->GetDIE(type_sp->GetID())); - if (defn_decl_ctx) - LinkDeclContextToDIE(defn_decl_ctx, die); return type_sp; } } + + if (attrs.is_forward_declaration) { + // See if the type comes from a Clang module and if so, track down + // that type. + TypeSP type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; + } + assert(tag_decl_kind != -1); UNUSED_IF_ASSERT_DISABLED(tag_decl_kind); - bool clang_type_was_created = false; - clang_type = CompilerType( - m_ast.weak_from_this(), - dwarf->GetForwardDeclDIEToCompilerType().lookup(die.GetDIE())); - if (!clang_type) { - clang::DeclContext *decl_ctx = - GetClangDeclContextContainingDIE(die, nullptr); + clang::DeclContext *containing_decl_ctx = + GetClangDeclContextContainingDIE(die, nullptr); - PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die, - attrs.name.GetCString()); + PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), + containing_decl_ctx, die, + attrs.name.GetCString()); - if (attrs.accessibility == eAccessNone && decl_ctx) { - // Check the decl context that contains this class/struct/union. If - // it is a class we must give it an accessibility. - const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind(); - if (DeclKindIsCXXClass(containing_decl_kind)) - attrs.accessibility = default_accessibility; - } + if (attrs.accessibility == eAccessNone && containing_decl_ctx) { + // Check the decl context that contains this class/struct/union. If + // it is a class we must give it an accessibility. + const clang::Decl::Kind containing_decl_kind = + containing_decl_ctx->getDeclKind(); + if (DeclKindIsCXXClass(containing_decl_kind)) + attrs.accessibility = default_accessibility; + } - ClangASTMetadata metadata; - metadata.SetUserID(die.GetID()); - metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); - - TypeSystemClang::TemplateParameterInfos template_param_infos; - if (ParseTemplateParameterInfos(die, template_param_infos)) { - clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl( - decl_ctx, GetOwningClangModule(die), attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, template_param_infos); - if (!class_template_decl) { - if (log) { - dwarf->GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF({0:p}) - {1:x16}: {2} type \"{3}\" " - "clang::ClassTemplateDecl failed to return a decl.", - static_cast<void *>(this), die.GetOffset(), - DW_TAG_value_to_name(tag), attrs.name.GetCString()); - } - return TypeSP(); + ClangASTMetadata metadata; + metadata.SetUserID(die.GetID()); + metadata.SetIsDynamicCXXType(dwarf->ClassOrStructIsVirtual(die)); + + TypeSystemClang::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos(die, template_param_infos)) { + clang::ClassTemplateDecl *class_template_decl = + m_ast.ParseClassTemplateDecl( + containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, template_param_infos); + if (!class_template_decl) { + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF({0:p}) - {1:x16}: {2} ({3}) type \"{4}\" " + "clang::ClassTemplateDecl failed to return a decl.", + static_cast<void *>(this), die.GetID(), DW_TAG_value_to_name(tag), + tag, attrs.name.GetCString()); } + return TypeSP(); + } - clang::ClassTemplateSpecializationDecl *class_specialization_decl = - m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, GetOwningClangModule(die), class_template_decl, - tag_decl_kind, template_param_infos); - clang_type = m_ast.CreateClassTemplateSpecializationType( - class_specialization_decl); - clang_type_was_created = true; + clang::ClassTemplateSpecializationDecl *class_specialization_decl = + m_ast.CreateClassTemplateSpecializationDecl( + containing_decl_ctx, GetOwningClangModule(die), class_template_decl, + tag_decl_kind, template_param_infos); + clang_type = + m_ast.CreateClassTemplateSpecializationType(class_specialization_decl); - m_ast.SetMetadata(class_template_decl, metadata); - m_ast.SetMetadata(class_specialization_decl, metadata); - } + m_ast.SetMetadata(class_template_decl, metadata); + m_ast.SetMetadata(class_specialization_decl, metadata); + } - if (!clang_type_was_created) { - clang_type_was_created = true; - clang_type = m_ast.CreateRecordType( - decl_ctx, GetOwningClangModule(die), attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, attrs.class_language, - &metadata, attrs.exports_symbols); - } + if (!clang_type) { + clang_type = m_ast.CreateRecordType( + containing_decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, attrs.class_language, &metadata, + attrs.exports_symbols); } - // Store a forward declaration to this class type in case any - // parameters in any class methods need it for the clang types for - // function prototypes. - LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = dwarf->MakeType( + TypeSP type_sp = dwarf->MakeType( die.GetID(), attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Forward, TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class)); + // Store a forward declaration to this class type in case any + // parameters in any class methods need it for the clang types for + // function prototypes. + clang::DeclContext *type_decl_ctx = + TypeSystemClang::GetDeclContextForType(clang_type); + LinkDeclContextToDIE(type_decl_ctx, die); + + // UniqueDWARFASTType is large, so don't create a local variables on the + // stack, put it on the heap. This function is often called recursively and + // clang isn't good at sharing the stack space for variables in different + // blocks. + auto unique_ast_entry_up = std::make_unique<UniqueDWARFASTType>(); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our // module unique_ast_entry_up->m_type_sp = type_sp; unique_ast_entry_up->m_die = die; unique_ast_entry_up->m_declaration = unique_decl; - unique_ast_entry_up->m_byte_size = attrs.byte_size.value_or(0); + unique_ast_entry_up->m_byte_size = byte_size; + unique_ast_entry_up->m_is_forward_declaration = attrs.is_forward_declaration; dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename, *unique_ast_entry_up); - if (!attrs.is_forward_declaration) { - // Always start the definition for a class type so that if the class - // has child classes or types that require the class to be created - // for use as their decl contexts the class will be ready to accept - // these child definitions. - if (!die.HasChildren()) { - // No children for this struct/union/class, lets finish it - if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { - TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); - } else { - dwarf->GetObjectFile()->GetModule()->ReportError( - - "DWARF DIE at {0:x16} named \"{1}\" was not able to start " - "its " - "definition.\nPlease file a bug and attach the file at the " - "start of this error message", - die.GetOffset(), attrs.name.GetCString()); - } - - // Setting authority byte size and alignment for empty structures. - // - // If the byte size or alignmenet of the record is specified then - // overwrite the ones that would be computed by Clang. - // This is only needed as LLDB's TypeSystemClang is always in C++ mode, - // but some compilers such as GCC and Clang give empty structs a size of 0 - // in C mode (in contrast to the size of 1 for empty structs that would be - // computed in C++ mode). - if (attrs.byte_size || attrs.alignment) { - clang::RecordDecl *record_decl = - TypeSystemClang::GetAsRecordDecl(clang_type); - if (record_decl) { - ClangASTImporter::LayoutInfo layout; - layout.bit_size = attrs.byte_size.value_or(0) * 8; - layout.alignment = attrs.alignment.value_or(0) * 8; - GetClangASTImporter().SetRecordLayout(record_decl, layout); - } - } - } else if (clang_type_was_created) { - // Start the definition if the class is not objective C since the - // underlying decls respond to isCompleteDefinition(). Objective - // C decls don't respond to isCompleteDefinition() so we can't - // start the declaration definition right away. For C++ - // class/union/structs we want to start the definition in case the - // class is needed as the declaration context for a contained class - // or type without the need to complete that type.. - - if (attrs.class_language != eLanguageTypeObjC && - attrs.class_language != eLanguageTypeObjC_plus_plus) - TypeSystemClang::StartTagDeclarationDefinition(clang_type); - - // Leave this as a forward declaration until we need to know the - // details of the type. lldb_private::Type will automatically call - // the SymbolFile virtual function - // "SymbolFileDWARF::CompleteType(Type *)" When the definition - // needs to be defined. - assert(!dwarf->GetForwardDeclCompilerTypeToDIE().count( - ClangUtil::RemoveFastQualifiers(clang_type) - .GetOpaqueQualType()) && - "Type already in the forward declaration map!"); - // Can't assume m_ast.GetSymbolFile() is actually a - // SymbolFileDWARF, it can be a SymbolFileDWARFDebugMap for Apple - // binaries. - dwarf->GetForwardDeclDIEToCompilerType()[die.GetDIE()] = - clang_type.GetOpaqueQualType(); - dwarf->GetForwardDeclCompilerTypeToDIE().try_emplace( - ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(), - *die.GetDIERef()); - m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); - } - } + // Leave this as a forward declaration until we need to know the + // details of the type. lldb_private::Type will automatically call + // the SymbolFile virtual function + // "SymbolFileDWARF::CompleteType(Type *)" When the definition + // needs to be defined. + bool inserted = + dwarf->GetForwardDeclCompilerTypeToDIE() + .try_emplace( + ClangUtil::RemoveFastQualifiers(clang_type).GetOpaqueQualType(), + *die.GetDIERef()) + .second; + assert(inserted && "Type already in the forward declaration map!"); + (void)inserted; + m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); // If we made a clang type, set the trivial abi if applicable: We only // do this for pass by value - which implies the Trivial ABI. There @@ -2164,87 +2082,82 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, ClangASTImporter::LayoutInfo layout_info; std::vector<DWARFDIE> contained_type_dies; - if (die.HasChildren()) { - const bool type_is_objc_object_or_interface = - TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type); - if (type_is_objc_object_or_interface) { - // For objective C we don't start the definition when the class is - // created. - TypeSystemClang::StartTagDeclarationDefinition(clang_type); - } - - AccessType default_accessibility = eAccessNone; - if (tag == DW_TAG_structure_type) { - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_union_type) { - default_accessibility = eAccessPublic; - } else if (tag == DW_TAG_class_type) { - default_accessibility = eAccessPrivate; - } - - std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; - // Parse members and base classes first - std::vector<DWARFDIE> member_function_dies; - - DelayedPropertyList delayed_properties; - ParseChildMembers(die, clang_type, bases, member_function_dies, - contained_type_dies, delayed_properties, - default_accessibility, layout_info); - - // Now parse any methods if there were any... - for (const DWARFDIE &die : member_function_dies) - dwarf->ResolveType(die); - - if (type_is_objc_object_or_interface) { - ConstString class_name(clang_type.GetTypeName()); - if (class_name) { - dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) { - method_die.ResolveType(); - return true; - }); + if (die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) + return false; // No definition, cannot complete. - for (DelayedAddObjCClassProperty &property : delayed_properties) - property.Finalize(); - } - } + // Start the definition if the type is not being defined already. This can + // happen (e.g.) when adding nested types to a class type -- see + // PrepareContextToReceiveMembers. + if (!clang_type.IsBeingDefined()) + TypeSystemClang::StartTagDeclarationDefinition(clang_type); - if (!bases.empty()) { - // Make sure all base classes refer to complete types and not forward - // declarations. If we don't do this, clang will crash with an - // assertion in the call to clang_type.TransferBaseClasses() - for (const auto &base_class : bases) { - clang::TypeSourceInfo *type_source_info = - base_class->getTypeSourceInfo(); - if (type_source_info) - TypeSystemClang::RequireCompleteType( - m_ast.GetType(type_source_info->getType())); - } + AccessType default_accessibility = eAccessNone; + if (tag == DW_TAG_structure_type) { + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_union_type) { + default_accessibility = eAccessPublic; + } else if (tag == DW_TAG_class_type) { + default_accessibility = eAccessPrivate; + } - m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), - std::move(bases)); + std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> bases; + // Parse members and base classes first + std::vector<DWARFDIE> member_function_dies; + + DelayedPropertyList delayed_properties; + ParseChildMembers(die, clang_type, bases, member_function_dies, + contained_type_dies, delayed_properties, + default_accessibility, layout_info); + + // Now parse any methods if there were any... + for (const DWARFDIE &die : member_function_dies) + dwarf->ResolveType(die); + + if (TypeSystemClang::IsObjCObjectOrInterfaceType(clang_type)) { + ConstString class_name(clang_type.GetTypeName()); + if (class_name) { + dwarf->GetObjCMethods(class_name, [&](DWARFDIE method_die) { + method_die.ResolveType(); + return true; + }); + + for (DelayedAddObjCClassProperty &property : delayed_properties) + property.Finalize(); } } + if (!bases.empty()) { + // Make sure all base classes refer to complete types and not forward + // declarations. If we don't do this, clang will crash with an + // assertion in the call to clang_type.TransferBaseClasses() + for (const auto &base_class : bases) { + clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); + if (type_source_info) + TypeSystemClang::RequireCompleteType( + m_ast.GetType(type_source_info->getType())); + } + + m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), std::move(bases)); + } + m_ast.AddMethodOverridesForCXXRecordType(clang_type.GetOpaqueQualType()); TypeSystemClang::BuildIndirectFields(clang_type); TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); - if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || - !layout_info.vbase_offsets.empty()) { - if (type) - layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8; - if (layout_info.bit_size == 0) - layout_info.bit_size = - die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; - if (layout_info.alignment == 0) - layout_info.alignment = - die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_alignment, 0) * 8; + if (type) + layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8; + if (layout_info.bit_size == 0) + layout_info.bit_size = + die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; + if (layout_info.alignment == 0) + layout_info.alignment = + die.GetAttributeValueAsUnsigned(llvm::dwarf::DW_AT_alignment, 0) * 8; + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) + GetClangASTImporter().SetRecordLayout(record_decl, layout_info); - clang::CXXRecordDecl *record_decl = - m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); - if (record_decl) - GetClangASTImporter().SetRecordLayout(record_decl, layout_info); - } // Now parse all contained types inside of the class. We make forward // declarations to all classes, but we need the CXXRecordDecl to have decls // for all contained types because we don't get asked for them via the @@ -2292,15 +2205,25 @@ bool DWARFASTParserClang::CompleteTypeFromDWARF(const DWARFDIE &die, case DW_TAG_structure_type: case DW_TAG_union_type: case DW_TAG_class_type: - return CompleteRecordType(die, type, clang_type); + CompleteRecordType(die, type, clang_type); + break; case DW_TAG_enumeration_type: - return CompleteEnumType(die, type, clang_type); + CompleteEnumType(die, type, clang_type); + break; default: assert(false && "not a forward clang type decl!"); break; } - return false; + // If the type is still not fully defined at this point, it means we weren't + // able to find its definition. We must forcefully complete it to preserve + // clang AST invariants. + if (clang_type.IsBeingDefined()) { + TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); + m_ast.SetDeclIsForcefullyCompleted(ClangUtil::GetAsTagDecl(clang_type)); + } + + return true; } void DWARFASTParserClang::EnsureAllDIEsInDeclContextHaveBeenParsed( @@ -2414,7 +2337,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) { std::vector<clang::ParmVarDecl *> param_decls; StreamString sstr; - DWARFDeclContext decl_ctx = SymbolFileDWARF::GetDWARFDeclContext(die); + DWARFDeclContext decl_ctx = die.GetDWARFDeclContext(); sstr << decl_ctx.GetQualifiedName(); clang::DeclContext *containing_decl_ctx = @@ -2998,11 +2921,11 @@ void DWARFASTParserClang::ParseSingleMember( this_field_info.bit_offset)))) { ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); objfile->GetModule()->ReportWarning( - "{0:x16}: {1} bitfield named \"{2}\" has invalid " - "bit offset ({3:x8}) member will be ignored. Please file a bug " + "{0:x16}: {1} ({2}) bitfield named \"{3}\" has invalid " + "bit offset ({4:x8}) member will be ignored. Please file a bug " "against the " - "compiler and include the preprocessed output for {4}\n", - die.GetID(), DW_TAG_value_to_name(tag), attrs.name, + "compiler and include the preprocessed output for {5}\n", + die.GetID(), DW_TAG_value_to_name(tag), tag, attrs.name, this_field_info.bit_offset, GetUnitName(parent_die).c_str()); return; } @@ -3762,7 +3685,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( if (dst_decl_ctx) src_dwarf_ast_parser->LinkDeclContextToDIE(dst_decl_ctx, src); - if (Type *src_child_type = die_to_type[src.GetDIE()]) + if (Type *src_child_type = die_to_type.lookup(src.GetDIE())) die_to_type[dst.GetDIE()] = src_child_type; }; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 8d4af203bb28..4b0ae026bce7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -23,6 +23,7 @@ #include "lldb/Core/PluginInterface.h" #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/Language/ObjC/ObjCLanguage.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include <optional> @@ -103,11 +104,14 @@ public: /// /// \param die The struct/class DWARFDIE containing template parameters. /// \return A string, including surrounding '<>', of the template parameters. - /// If the DIE's name already has '<>', returns an empty ConstString because + /// If the DIE's name already has '<>', returns an empty string because /// it's assumed that the caller is using the DIE name anyway. - lldb_private::ConstString GetDIEClassTemplateParams( + std::string GetDIEClassTemplateParams( const lldb_private::plugin::dwarf::DWARFDIE &die) override; + void MapDeclDIEToDefDIE(const lldb_private::plugin::dwarf::DWARFDIE &decl_die, + const lldb_private::plugin::dwarf::DWARFDIE &def_die); + protected: /// Protected typedefs and members. /// @{ @@ -167,8 +171,10 @@ protected: lldb_private::TypeSystemClang::TemplateParameterInfos &template_param_infos); - std::string - GetCPlusPlusQualifiedName(const lldb_private::plugin::dwarf::DWARFDIE &die); + void GetUniqueTypeNameAndDeclaration( + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb::LanguageType language, lldb_private::ConstString &unique_typename, + lldb_private::Declaration &decl_declaration); bool ParseChildMembers( const lldb_private::plugin::dwarf::DWARFDIE &die, @@ -370,6 +376,56 @@ private: ParsedDWARFTypeAttributes &attrs); lldb::TypeSP ParseSubroutine(const lldb_private::plugin::dwarf::DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); + + /// Helper function called by \ref ParseSubroutine when parsing ObjC-methods. + /// + /// \param[in] objc_method Name of the ObjC method being parsed. + /// + /// \param[in] die The DIE that represents the ObjC method being parsed. + /// + /// \param[in] clang_type The CompilerType representing the function prototype + /// of the ObjC method being parsed. + /// + /// \param[in] attrs DWARF attributes for \ref die. + /// + /// \param[in] is_variadic Is true iff we're parsing a variadic method. + /// + /// \returns true on success + bool + ParseObjCMethod(const lldb_private::ObjCLanguage::MethodName &objc_method, + const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::CompilerType clang_type, + const ParsedDWARFTypeAttributes &attrs, bool is_variadic); + + /// Helper function called by \ref ParseSubroutine when parsing C++ methods. + /// + /// \param[in] die The DIE that represents the C++ method being parsed. + /// + /// \param[in] clang_type The CompilerType representing the function prototype + /// of the C++ method being parsed. + /// + /// \param[in] attrs DWARF attributes for \ref die. + /// + /// \param[in] decl_ctx_die The DIE representing the DeclContext of the C++ + /// method being parsed. + /// + /// \param[in] is_static Is true iff we're parsing a static method. + /// + /// \param[out] ignore_containing_context Will get set to true if the caller + /// should treat this C++ method as-if it was not a C++ method. + /// Currently used as a hack to work around templated C++ methods + /// causing class definitions to mismatch between CUs. + /// + /// \returns A pair of <bool, TypeSP>. The first element is 'true' on success. + /// The second element is non-null if we have previously parsed this + /// method (a null TypeSP does not indicate failure). + std::pair<bool, lldb::TypeSP> + ParseCXXMethod(const lldb_private::plugin::dwarf::DWARFDIE &die, + lldb_private::CompilerType clang_type, + const ParsedDWARFTypeAttributes &attrs, + const lldb_private::plugin::dwarf::DWARFDIE &decl_ctx_die, + bool is_static, bool &ignore_containing_context); + lldb::TypeSP ParseArrayType(const lldb_private::plugin::dwarf::DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); lldb::TypeSP diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp index 3a3b05acd26d..c2ebeed4c860 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.cpp @@ -35,10 +35,6 @@ dw_tag_t DWARFBaseDIE::Tag() const { return llvm::dwarf::DW_TAG_null; } -const char *DWARFBaseDIE::GetTagAsCString() const { - return DW_TAG_value_to_name(Tag()); -} - const char *DWARFBaseDIE::GetAttributeValueAsString(const dw_attr_t attr, const char *fail_value) const { if (IsValid()) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h index 75c822703cd8..235343d22712 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -85,8 +85,6 @@ public: // Accessing information about a DIE dw_tag_t Tag() const; - const char *GetTagAsCString() const; - dw_offset_t GetOffset() const; // Get the LLDB user ID for this DIE. This is often just the DIE offset, diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index dd130977d4b1..b8344f548ac3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -32,7 +32,7 @@ public: private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, - const DWARFUnitHeader &header, + const llvm::DWARFUnitHeader &header, const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index d4446befd83b..fb32e2adeb3f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -13,8 +13,10 @@ #include "DWARFDebugInfoEntry.h" #include "DWARFDeclContext.h" #include "DWARFUnit.h" +#include "lldb/Symbol/Type.h" #include "llvm/ADT/iterator.h" +#include "llvm/BinaryFormat/Dwarf.h" using namespace lldb_private; using namespace lldb_private::dwarf; @@ -316,8 +318,14 @@ void DWARFDIE::AppendTypeName(Stream &s) const { GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_extra_discriminator, 0); bool isaPointer = GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_isa_pointer, 0); - s.Printf("__ptrauth(%d, %d, 0x0%x, %d)", key, isAddressDiscriminated, - extraDiscriminator, isaPointer); + bool authenticatesNullValues = GetAttributeValueAsUnsigned( + DW_AT_LLVM_ptrauth_authenticates_null_values, 0); + unsigned authenticationMode = + GetAttributeValueAsUnsigned(DW_AT_LLVM_ptrauth_authentication_mode, 3); + + s.Printf("__ptrauth(%d, %d, 0x0%x, %d, %d, %d)", key, + isAddressDiscriminated, extraDiscriminator, isaPointer, + authenticatesNullValues, authenticationMode); break; } default: @@ -359,131 +367,198 @@ lldb_private::Type *DWARFDIE::ResolveTypeUID(const DWARFDIE &die) const { return nullptr; } -std::vector<DWARFDIE> DWARFDIE::GetDeclContextDIEs() const { - if (!IsValid()) - return {}; +static void GetDeclContextImpl(DWARFDIE die, + llvm::SmallSet<lldb::user_id_t, 4> &seen, + std::vector<CompilerContext> &context) { + // Stop if we hit a cycle. + while (die && seen.insert(die.GetID()).second) { + // Handle outline member function DIEs by following the specification. + if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) { + die = spec; + continue; + } + // To find the name of a type in a type unit, we must follow the signature. + if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) { + die = spec; + continue; + } - std::vector<DWARFDIE> result; - DWARFDIE parent = GetParentDeclContextDIE(); - while (parent.IsValid() && parent.GetDIE() != GetDIE()) { - result.push_back(std::move(parent)); - parent = parent.GetParentDeclContextDIE(); + // Add this DIE's contribution at the end of the chain. + auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { + context.push_back({kind, ConstString(name)}); + }; + switch (die.Tag()) { + case DW_TAG_module: + push_ctx(CompilerContextKind::Module, die.GetName()); + break; + case DW_TAG_namespace: + push_ctx(CompilerContextKind::Namespace, die.GetName()); + break; + case DW_TAG_class_type: + case DW_TAG_structure_type: + push_ctx(CompilerContextKind::ClassOrStruct, die.GetName()); + break; + case DW_TAG_union_type: + push_ctx(CompilerContextKind::Union, die.GetName()); + break; + case DW_TAG_enumeration_type: + push_ctx(CompilerContextKind::Enum, die.GetName()); + break; + case DW_TAG_subprogram: + push_ctx(CompilerContextKind::Function, die.GetName()); + break; + case DW_TAG_variable: + push_ctx(CompilerContextKind::Variable, die.GetPubname()); + break; + case DW_TAG_typedef: + push_ctx(CompilerContextKind::Typedef, die.GetName()); + break; + default: + break; + } + // Now process the parent. + die = die.GetParent(); } +} - return result; +std::vector<CompilerContext> DWARFDIE::GetDeclContext() const { + llvm::SmallSet<lldb::user_id_t, 4> seen; + std::vector<CompilerContext> context; + GetDeclContextImpl(*this, seen, context); + std::reverse(context.begin(), context.end()); + return context; } -static std::vector<lldb_private::CompilerContext> -GetDeclContextImpl(llvm::SmallSet<lldb::user_id_t, 4> &seen, DWARFDIE die) { - std::vector<lldb_private::CompilerContext> context; +static void GetTypeLookupContextImpl(DWARFDIE die, + llvm::SmallSet<lldb::user_id_t, 4> &seen, + std::vector<CompilerContext> &context) { // Stop if we hit a cycle. - if (!die || !seen.insert(die.GetID()).second) - return context; + while (die && seen.insert(die.GetID()).second) { + // To find the name of a type in a type unit, we must follow the signature. + if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_signature)) { + die = spec; + continue; + } - // Handle outline member function DIEs by following the specification. - if (DWARFDIE spec = die.GetReferencedDIE(DW_AT_specification)) - return GetDeclContextImpl(seen, spec); + // If there is no name, then there is no need to look anything up for this + // DIE. + const char *name = die.GetName(); + if (!name || !name[0]) + return; + + // Add this DIE's contribution at the end of the chain. + auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { + context.push_back({kind, ConstString(name)}); + }; + switch (die.Tag()) { + case DW_TAG_namespace: + push_ctx(CompilerContextKind::Namespace, die.GetName()); + break; + case DW_TAG_class_type: + case DW_TAG_structure_type: + push_ctx(CompilerContextKind::ClassOrStruct, die.GetName()); + break; + case DW_TAG_union_type: + push_ctx(CompilerContextKind::Union, die.GetName()); + break; + case DW_TAG_enumeration_type: + push_ctx(CompilerContextKind::Enum, die.GetName()); + break; + case DW_TAG_variable: + push_ctx(CompilerContextKind::Variable, die.GetPubname()); + break; + case DW_TAG_typedef: + push_ctx(CompilerContextKind::Typedef, die.GetName()); + break; + case DW_TAG_base_type: + push_ctx(CompilerContextKind::Builtin, name); + break; + // If any of the tags below appear in the parent chain, stop the decl + // context and return. Prior to these being in here, if a type existed in a + // namespace "a" like "a::my_struct", but we also have a function in that + // same namespace "a" which contained a type named "my_struct", both would + // return "a::my_struct" as the declaration context since the + // DW_TAG_subprogram would be skipped and its parent would be found. + case DW_TAG_compile_unit: + case DW_TAG_type_unit: + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + return; + default: + break; + } + // Now process the parent. + die = die.GetParent(); + } +} - // Get the parent context chain. - context = GetDeclContextImpl(seen, die.GetParent()); +std::vector<CompilerContext> DWARFDIE::GetTypeLookupContext() const { + llvm::SmallSet<lldb::user_id_t, 4> seen; + std::vector<CompilerContext> context; + GetTypeLookupContextImpl(*this, seen, context); + std::reverse(context.begin(), context.end()); + return context; +} - // Add this DIE's contribution at the end of the chain. - auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { - context.push_back({kind, ConstString(name)}); - }; - switch (die.Tag()) { - case DW_TAG_module: - push_ctx(CompilerContextKind::Module, die.GetName()); - break; - case DW_TAG_namespace: - push_ctx(CompilerContextKind::Namespace, die.GetName()); - break; - case DW_TAG_structure_type: - push_ctx(CompilerContextKind::Struct, die.GetName()); - break; - case DW_TAG_union_type: - push_ctx(CompilerContextKind::Union, die.GetName()); - break; - case DW_TAG_class_type: - push_ctx(CompilerContextKind::Class, die.GetName()); - break; - case DW_TAG_enumeration_type: - push_ctx(CompilerContextKind::Enum, die.GetName()); - break; - case DW_TAG_subprogram: - push_ctx(CompilerContextKind::Function, die.GetName()); - break; - case DW_TAG_variable: - push_ctx(CompilerContextKind::Variable, die.GetPubname()); - break; - case DW_TAG_typedef: - push_ctx(CompilerContextKind::Typedef, die.GetName()); - break; - default: - break; +static DWARFDeclContext GetDWARFDeclContextImpl(DWARFDIE die) { + DWARFDeclContext dwarf_decl_ctx; + while (die) { + const dw_tag_t tag = die.Tag(); + if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) + break; + dwarf_decl_ctx.AppendDeclContext(tag, die.GetName()); + DWARFDIE parent_decl_ctx_die = die.GetParentDeclContextDIE(); + if (parent_decl_ctx_die == die) + break; + die = parent_decl_ctx_die; } - return context; + return dwarf_decl_ctx; } -std::vector<lldb_private::CompilerContext> DWARFDIE::GetDeclContext() const { - llvm::SmallSet<lldb::user_id_t, 4> seen; - return GetDeclContextImpl(seen, *this); +DWARFDeclContext DWARFDIE::GetDWARFDeclContext() const { + return GetDWARFDeclContextImpl(*this); } -std::vector<lldb_private::CompilerContext> -DWARFDIE::GetTypeLookupContext() const { - std::vector<lldb_private::CompilerContext> context; - // If there is no name, then there is no need to look anything up for this - // DIE. - const char *name = GetName(); - if (!name || !name[0]) - return context; - const dw_tag_t tag = Tag(); - if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) - return context; - DWARFDIE parent = GetParent(); - if (parent) - context = parent.GetTypeLookupContext(); - auto push_ctx = [&](CompilerContextKind kind, llvm::StringRef name) { - context.push_back({kind, ConstString(name)}); - }; - switch (tag) { - case DW_TAG_namespace: - push_ctx(CompilerContextKind::Namespace, name); - break; - case DW_TAG_structure_type: - push_ctx(CompilerContextKind::Struct, name); - break; - case DW_TAG_union_type: - push_ctx(CompilerContextKind::Union, name); - break; - case DW_TAG_class_type: - push_ctx(CompilerContextKind::Class, name); - break; - case DW_TAG_enumeration_type: - push_ctx(CompilerContextKind::Enum, name); - break; - case DW_TAG_variable: - push_ctx(CompilerContextKind::Variable, GetPubname()); - break; - case DW_TAG_typedef: - push_ctx(CompilerContextKind::Typedef, name); - break; - case DW_TAG_base_type: - push_ctx(CompilerContextKind::Builtin, name); - break; - default: - break; +static DWARFDIE GetParentDeclContextDIEImpl(DWARFDIE die) { + DWARFDIE orig_die = die; + while (die) { + // If this is the original DIE that we are searching for a declaration for, + // then don't look in the cache as we don't want our own decl context to be + // our decl context... + if (die != orig_die) { + switch (die.Tag()) { + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + case DW_TAG_namespace: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + return die; + + default: + break; + } + } + + if (DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification)) { + if (DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE()) + return decl_ctx_die; + } + + if (DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin)) { + if (DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE()) + return decl_ctx_die; + } + + die = die.GetParent(); } - return context; + return DWARFDIE(); } DWARFDIE DWARFDIE::GetParentDeclContextDIE() const { - if (IsValid()) - return m_die->GetParentDeclContextDIE(m_cu); - else - return DWARFDIE(); + return GetParentDeclContextDIEImpl(*this); } bool DWARFDIE::IsStructUnionOrClass() const { diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 511ca62d0197..e1318953a384 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -69,9 +69,6 @@ public: DWARFDIE GetParentDeclContextDIE() const; - // DeclContext related functions - std::vector<DWARFDIE> GetDeclContextDIEs() const; - /// Return this DIE's decl context as it is needed to look up types /// in Clang modules. This context will include any modules or functions that /// the type is declared in so an exact module match can be efficiently made. @@ -89,6 +86,8 @@ public: /// using a full or partial CompilerContext array. std::vector<CompilerContext> GetTypeLookupContext() const; + DWARFDeclContext GetDWARFDeclContext() const; + // Getting attribute values from the DIE. // // GetAttributeValueAsXXX() functions should only be used if you are diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index da73891f6665..f383261e8a5f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -89,8 +89,7 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc, } void DWARFDebugAranges::Sort(bool minimize) { - LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); + LLDB_SCOPED_TIMER(); m_aranges.Sort(); m_aranges.CombineConsecutiveEntriesWithEqualData(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 340b9acf80d0..f7df38d24019 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -24,6 +24,7 @@ #include "DWARFDebugInfoEntry.h" #include "DWARFFormValue.h" #include "DWARFTypeUnit.h" +#include "LogChannelDWARF.h" using namespace lldb; using namespace lldb_private; @@ -81,27 +82,94 @@ void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { : m_context.getOrLoadDebugInfoData(); lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { - llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract( - m_dwarf, m_units.size(), data, section, &offset); + const lldb::offset_t unit_header_offset = offset; + llvm::Expected<DWARFUnitSP> expected_unit_sp = + DWARFUnit::extract(m_dwarf, m_units.size(), data, section, &offset); - if (!unit_sp) { - // FIXME: Propagate this error up. - llvm::consumeError(unit_sp.takeError()); + if (!expected_unit_sp) { + Log *log = GetLog(DWARFLog::DebugInfo); + if (log) + LLDB_LOG(log, "Unable to extract DWARFUnitHeader at {0:x}: {1}", + unit_header_offset, + llvm::toString(expected_unit_sp.takeError())); + else + llvm::consumeError(expected_unit_sp.takeError()); return; } + DWARFUnitSP unit_sp = *expected_unit_sp; + // If it didn't return an error, then it should be returning a valid Unit. - assert(*unit_sp); - m_units.push_back(*unit_sp); - offset = (*unit_sp)->GetNextUnitOffset(); + assert((bool)unit_sp); + + // Keep a map of DWO ID back to the skeleton units. Sometimes accelerator + // table lookups can cause the DWO files to be accessed before the skeleton + // compile unit is parsed, so we keep a map to allow us to match up the DWO + // file to the back to the skeleton compile units. + if (unit_sp->GetUnitType() == lldb_private::dwarf::DW_UT_skeleton) { + if (std::optional<uint64_t> unit_dwo_id = unit_sp->GetHeaderDWOId()) + m_dwarf5_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit_sp.get(); + } - if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) { + m_units.push_back(unit_sp); + offset = unit_sp->GetNextUnitOffset(); + + if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp.get())) { m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(), - unit_sp.get()->GetID()); + unit_sp->GetID()); } } } +DWARFUnit *DWARFDebugInfo::GetSkeletonUnit(DWARFUnit *dwo_unit) { + // If this isn't a DWO unit, don't try and find the skeleton unit. + if (!dwo_unit->IsDWOUnit()) + return nullptr; + + auto dwo_id = dwo_unit->GetDWOId(); + if (!dwo_id.has_value()) + return nullptr; + + // Parse the unit headers so that m_dwarf5_dwo_id_to_skeleton_unit is filled + // in with all of the DWARF5 skeleton compile units DWO IDs since it is easy + // to access the DWO IDs in the DWARFUnitHeader for each DWARFUnit. + ParseUnitHeadersIfNeeded(); + + // Find the value in our cache and return it we we find it. This cache may + // only contain DWARF5 units. + auto iter = m_dwarf5_dwo_id_to_skeleton_unit.find(*dwo_id); + if (iter != m_dwarf5_dwo_id_to_skeleton_unit.end()) + return iter->second; + + // DWARF5 unit headers have the DWO ID and should have already been in the map + // so if it wasn't found in the above find() call, then we didn't find it and + // don't need to do the more expensive DWARF4 search. + if (dwo_unit->GetVersion() >= 5) + return nullptr; + + // Parse all DWO IDs from all DWARF4 and earlier compile units that have DWO + // IDs. It is more expensive to get the DWO IDs from DWARF4 compile units as + // we need to parse the unit DIE and extract the DW_AT_dwo_id or + // DW_AT_GNU_dwo_id attribute values, so do this only if we didn't find our + // match above search and only for DWARF4 and earlier compile units. + llvm::call_once(m_dwarf4_dwo_id_to_skeleton_unit_once_flag, [this]() { + for (uint32_t i = 0, num = GetNumUnits(); i < num; ++i) { + if (DWARFUnit *unit = GetUnitAtIndex(i)) { + if (unit->GetVersion() < 5) { + if (std::optional<uint64_t> unit_dwo_id = unit->GetDWOId()) + m_dwarf4_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit; + } + } + } + }); + + // Search the DWARF4 DWO results that we parsed lazily. + iter = m_dwarf4_dwo_id_to_skeleton_unit.find(*dwo_id); + if (iter != m_dwarf4_dwo_id_to_skeleton_unit.end()) + return iter->second; + return nullptr; +} + void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { llvm::call_once(m_units_once_flag, [&] { ParseUnitsFor(DIERef::Section::DebugInfo); @@ -154,10 +222,6 @@ DWARFUnit *DWARFDebugInfo::GetUnitAtOffset(DIERef::Section section, return result; } -DWARFUnit *DWARFDebugInfo::GetUnit(const DIERef &die_ref) { - return GetUnitContainingDIEOffset(die_ref.section(), die_ref.die_offset()); -} - DWARFUnit * DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset) { @@ -168,6 +232,10 @@ DWARFDebugInfo::GetUnitContainingDIEOffset(DIERef::Section section, return result; } +const std::shared_ptr<SymbolFileDWARFDwo> &DWARFDebugInfo::GetDwpSymbolFile() { + return m_dwarf.GetDwpSymbolFile(); +} + DWARFTypeUnit *DWARFDebugInfo::GetTypeUnitForHash(uint64_t hash) { auto pos = llvm::lower_bound(m_type_hash_to_unit_index, std::make_pair(hash, 0u), llvm::less_first()); @@ -185,15 +253,8 @@ bool DWARFDebugInfo::ContainsTypeUnits() { // // Get the DIE (Debug Information Entry) with the specified offset. DWARFDIE -DWARFDebugInfo::GetDIE(const DIERef &die_ref) { - DWARFUnit *cu = GetUnit(die_ref); - if (cu) - return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); +DWARFDebugInfo::GetDIE(DIERef::Section section, dw_offset_t die_offset) { + if (DWARFUnit *cu = GetUnitContainingDIEOffset(section, die_offset)) + return cu->GetNonSkeletonUnit().GetDIE(die_offset); return DWARFDIE(); // Not found } - -llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) { - if (DWARFUnit *cu = GetUnit(die_ref)) - return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset()); - return llvm::StringRef(); -} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index a8b5abc3beed..598739bf3cb9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -38,15 +38,10 @@ public: uint32_t *idx_ptr = nullptr); DWARFUnit *GetUnitContainingDIEOffset(DIERef::Section section, dw_offset_t die_offset); - DWARFUnit *GetUnit(const DIERef &die_ref); + DWARFUnit *GetSkeletonUnit(DWARFUnit *dwo_unit); DWARFTypeUnit *GetTypeUnitForHash(uint64_t hash); bool ContainsTypeUnits(); - DWARFDIE GetDIE(const DIERef &die_ref); - - /// Returns the AT_Name of this DIE, if it exists, without parsing the entire - /// compile unit. An empty is string is returned upon error or if the - /// attribute is not present. - llvm::StringRef PeekDIEName(const DIERef &die_ref); + DWARFDIE GetDIE(DIERef::Section section, dw_offset_t die_offset); enum { eDumpFlag_Verbose = (1 << 0), // Verbose dumping @@ -57,6 +52,8 @@ public: const DWARFDebugAranges &GetCompileUnitAranges(); + const std::shared_ptr<SymbolFileDWARFDwo> &GetDwpSymbolFile(); + protected: typedef std::vector<DWARFUnitSP> UnitColl; @@ -70,6 +67,9 @@ protected: m_cu_aranges_up; // A quick address to compile unit table std::vector<std::pair<uint64_t, uint32_t>> m_type_hash_to_unit_index; + llvm::DenseMap<uint64_t, DWARFUnit *> m_dwarf5_dwo_id_to_skeleton_unit; + llvm::DenseMap<uint64_t, DWARFUnit *> m_dwarf4_dwo_id_to_skeleton_unit; + llvm::once_flag m_dwarf4_dwo_id_to_skeleton_unit_once_flag; private: // All parsing needs to be done partially any managed by this class as diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 1b0fefedf983..e2660735ea7d 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -11,6 +11,7 @@ #include <cassert> #include <algorithm> +#include <limits> #include <optional> #include "llvm/Support/LEB128.h" @@ -41,13 +42,23 @@ extern int g_verbose; // Extract a debug info entry for a given DWARFUnit from the data // starting at the offset in offset_ptr bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, - const DWARFUnit *cu, + const DWARFUnit &unit, lldb::offset_t *offset_ptr) { m_offset = *offset_ptr; + auto report_error = [&](const char *fmt, const auto &...vals) { + unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "[{0:x16}]: {1}, please file a bug and " + "attach the file at the start of this error message", + static_cast<uint64_t>(m_offset), llvm::formatv(fmt, vals...)); + *offset_ptr = std::numeric_limits<lldb::offset_t>::max(); + return false; + }; + m_parent_idx = 0; m_sibling_idx = 0; const uint64_t abbr_idx = data.GetULEB128(offset_ptr); - lldbassert(abbr_idx <= UINT16_MAX); + if (abbr_idx > std::numeric_limits<uint16_t>::max()) + return report_error("abbreviation code {0} too big", abbr_idx); m_abbr_idx = abbr_idx; if (m_abbr_idx == 0) { @@ -56,31 +67,18 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, return true; // NULL debug tag entry } - const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); - if (abbrevDecl == nullptr) { - cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "[{0:x16}]: invalid abbreviation code {1}, " - "please file a bug and " - "attach the file at the start of this error message", - (uint64_t)m_offset, (unsigned)abbr_idx); - // WE can't parse anymore if the DWARF is borked... - *offset_ptr = UINT32_MAX; - return false; - } + const auto *abbrevDecl = GetAbbreviationDeclarationPtr(&unit); + if (abbrevDecl == nullptr) + return report_error("invalid abbreviation code {0}", abbr_idx); + m_tag = abbrevDecl->getTag(); m_has_children = abbrevDecl->hasChildren(); // Skip all data in the .debug_info or .debug_types for the attributes for (const auto &attribute : abbrevDecl->attributes()) { - if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, cu)) + if (DWARFFormValue::SkipValue(attribute.Form, data, offset_ptr, &unit)) continue; - cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "[{0:x16}]: Unsupported DW_FORM_{1:x}, please file a bug " - "and " - "attach the file at the start of this error message", - (uint64_t)m_offset, (unsigned)attribute.Form); - *offset_ptr = m_offset; - return false; + return report_error("Unsupported DW_FORM_{1:x}", attribute.Form); } return true; } @@ -612,79 +610,6 @@ void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( } } -DWARFDeclContext -DWARFDebugInfoEntry::GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, - DWARFUnit *cu) { - DWARFDeclContext dwarf_decl_ctx; - for (;;) { - const dw_tag_t tag = die->Tag(); - if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit) - return dwarf_decl_ctx; - dwarf_decl_ctx.AppendDeclContext(tag, die->GetName(cu)); - DWARFDIE parent_decl_ctx_die = die->GetParentDeclContextDIE(cu); - if (!parent_decl_ctx_die || parent_decl_ctx_die.GetDIE() == die) - return dwarf_decl_ctx; - if (parent_decl_ctx_die.Tag() == DW_TAG_compile_unit || - parent_decl_ctx_die.Tag() == DW_TAG_partial_unit) - return dwarf_decl_ctx; - die = parent_decl_ctx_die.GetDIE(); - cu = parent_decl_ctx_die.GetCU(); - } -} - -DWARFDeclContext DWARFDebugInfoEntry::GetDWARFDeclContext(DWARFUnit *cu) const { - return GetDWARFDeclContextStatic(this, cu); -} - -DWARFDIE -DWARFDebugInfoEntry::GetParentDeclContextDIE(DWARFUnit *cu) const { - DWARFAttributes attributes = GetAttributes(cu, Recurse::yes); - return GetParentDeclContextDIE(cu, attributes); -} - -DWARFDIE -DWARFDebugInfoEntry::GetParentDeclContextDIE( - DWARFUnit *cu, const DWARFAttributes &attributes) const { - DWARFDIE die(cu, const_cast<DWARFDebugInfoEntry *>(this)); - - while (die) { - // If this is the original DIE that we are searching for a declaration for, - // then don't look in the cache as we don't want our own decl context to be - // our decl context... - if (die.GetDIE() != this) { - switch (die.Tag()) { - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - case DW_TAG_namespace: - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_class_type: - return die; - - default: - break; - } - } - - DWARFDIE spec_die = attributes.FormValueAsReference(DW_AT_specification); - if (spec_die) { - DWARFDIE decl_ctx_die = spec_die.GetParentDeclContextDIE(); - if (decl_ctx_die) - return decl_ctx_die; - } - - DWARFDIE abs_die = attributes.FormValueAsReference(DW_AT_abstract_origin); - if (abs_die) { - DWARFDIE decl_ctx_die = abs_die.GetParentDeclContextDIE(); - if (decl_ctx_die) - return decl_ctx_die; - } - - die = die.GetParent(); - } - return DWARFDIE(); -} - lldb::offset_t DWARFDebugInfoEntry::GetFirstAttributeOffset() const { return GetOffset() + llvm::getULEB128Size(m_abbr_idx); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index c19fa7428549..3816c6500717 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -49,7 +49,7 @@ public: void BuildFunctionAddressRangeTable(DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; - bool Extract(const DWARFDataExtractor &data, const DWARFUnit *cu, + bool Extract(const DWARFDataExtractor &data, const DWARFUnit &cu, lldb::offset_t *offset_ptr); using Recurse = DWARFBaseDIE::Recurse; @@ -157,12 +157,6 @@ public: return HasChildren() ? this + 1 : nullptr; } - DWARFDeclContext GetDWARFDeclContext(DWARFUnit *cu) const; - - DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu) const; - DWARFDIE GetParentDeclContextDIE(DWARFUnit *cu, - const DWARFAttributes &attributes) const; - void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; } void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } @@ -172,9 +166,6 @@ public: bool IsGlobalOrStaticScopeVariable() const; protected: - static DWARFDeclContext - GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, DWARFUnit *cu); - // Up to 2TB offset within the .debug_info/.debug_types dw_offset_t m_offset : DW_DIE_OFFSET_MAX_BITSIZE; // How many to subtract from "this" to get the parent. If zero this die has no diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp index 44421c0eda3e..f759cb8fae61 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp @@ -12,18 +12,16 @@ using namespace lldb_private::dwarf; using namespace lldb_private::plugin::dwarf; -/// Returns the name of `entry` if it has one, or the appropriate "anonymous -/// {namespace, class, struct, union}". -static const char *GetName(DWARFDeclContext::Entry entry) { - if (entry.name != nullptr) - return entry.name; - if (entry.tag == DW_TAG_namespace) +const char *DWARFDeclContext::Entry::GetName() const { + if (name != nullptr) + return name; + if (tag == DW_TAG_namespace) return "(anonymous namespace)"; - if (entry.tag == DW_TAG_class_type) + if (tag == DW_TAG_class_type) return "(anonymous class)"; - if (entry.tag == DW_TAG_structure_type) + if (tag == DW_TAG_structure_type) return "(anonymous struct)"; - if (entry.tag == DW_TAG_union_type) + if (tag == DW_TAG_union_type) return "(anonymous union)"; return "(anonymous)"; } @@ -46,7 +44,7 @@ const char *DWARFDeclContext::GetQualifiedName() const { llvm::raw_string_ostream string_stream(m_qualified_name); llvm::interleave( llvm::reverse(m_entries), string_stream, - [&](auto entry) { string_stream << GetName(entry); }, "::"); + [&](auto entry) { string_stream << entry.GetName(); }, "::"); } } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index a20a862d3402..b563d1c4417b 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -9,8 +9,9 @@ #ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H -#include "lldb/Utility/ConstString.h" #include "DWARFDefines.h" +#include "lldb/Utility/ConstString.h" +#include "llvm/ADT/StringExtras.h" #include <cassert> #include <string> @@ -38,6 +39,10 @@ public: return false; } + /// Returns the name of this entry if it has one, or the appropriate + /// "anonymous {namespace, class, struct, union}". + const char *GetName() const; + // Test operator explicit operator bool() const { return tag != 0; } @@ -47,6 +52,10 @@ public: DWARFDeclContext() : m_entries() {} + DWARFDeclContext(llvm::ArrayRef<Entry> entries) { + llvm::append_range(m_entries, entries); + } + void AppendDeclContext(dw_tag_t tag, const char *name) { m_entries.push_back(Entry(tag, name)); } @@ -79,6 +88,17 @@ public: m_qualified_name.clear(); } + friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const DWARFDeclContext &ctx) { + OS << "DWARFDeclContext{"; + llvm::ListSeparator LS; + for (const Entry &e : ctx.m_entries) { + OS << LS << "{" << DW_TAG_value_to_name(e.tag) << ", " << e.GetName() + << "}"; + } + return OS << "}"; + } + protected: typedef std::vector<Entry> collection; collection m_entries; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp index 9a88aed85e97..2fb0c224bf8e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp @@ -15,38 +15,12 @@ namespace lldb_private::plugin { namespace dwarf { -const char *DW_TAG_value_to_name(uint32_t val) { - static char invalid[100]; - - if (val == 0) - return "NULL"; +llvm::StringRef DW_TAG_value_to_name(dw_tag_t tag) { + static constexpr llvm::StringLiteral s_unknown_tag_name("<unknown DW_TAG>"); + if (llvm::StringRef tag_name = llvm::dwarf::TagString(tag); !tag_name.empty()) + return tag_name; - llvm::StringRef llvmstr = llvm::dwarf::TagString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_TAG constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - -const char *DW_AT_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::AttributeString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_AT constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - -const char *DW_FORM_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::FormEncodingString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_FORM constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); + return s_unknown_tag_name; } const char *DW_OP_value_to_name(uint32_t val) { @@ -59,35 +33,5 @@ const char *DW_OP_value_to_name(uint32_t val) { return llvmstr.data(); } -const char *DW_ATE_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::AttributeEncodingString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_ATE constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - -const char *DW_LANG_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::LanguageString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_LANG constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - -const char *DW_LNS_value_to_name(uint32_t val) { - static char invalid[100]; - llvm::StringRef llvmstr = llvm::dwarf::LNStandardString(val); - if (llvmstr.empty()) { - snprintf(invalid, sizeof(invalid), "Unknown DW_LNS constant: 0x%x", val); - return invalid; - } - return llvmstr.data(); -} - } // namespace dwarf } // namespace lldb_private::plugin diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 3ed92cc203bf..be81cb0f5df1 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -15,22 +15,10 @@ namespace lldb_private::plugin { namespace dwarf { -typedef uint32_t DRC_class; // Holds DRC_* class bitfields - -const char *DW_TAG_value_to_name(uint32_t val); - -const char *DW_AT_value_to_name(uint32_t val); - -const char *DW_FORM_value_to_name(uint32_t val); +llvm::StringRef DW_TAG_value_to_name(dw_tag_t tag); const char *DW_OP_value_to_name(uint32_t val); -const char *DW_ATE_value_to_name(uint32_t val); - -const char *DW_LANG_value_to_name(uint32_t val); - -const char *DW_LNS_value_to_name(uint32_t val); - } // namespace dwarf } // namespace lldb_private::plugin diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp index 20c07a94b507..eafddbad03f5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.cpp @@ -24,16 +24,11 @@ using namespace lldb_private::plugin::dwarf; DWARFIndex::~DWARFIndex() = default; bool DWARFIndex::ProcessFunctionDIE( - const Module::LookupInfo &lookup_info, DIERef ref, SymbolFileDWARF &dwarf, + const Module::LookupInfo &lookup_info, DWARFDIE die, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref<bool(DWARFDIE die)> callback) { llvm::StringRef name = lookup_info.GetLookupName().GetStringRef(); FunctionNameType name_type_mask = lookup_info.GetNameTypeMask(); - DWARFDIE die = dwarf.GetDIE(ref); - if (!die) { - ReportInvalidDIERef(ref, name); - return true; - } if (!(name_type_mask & eFunctionNameTypeFull)) { ConstString name_to_match_against; @@ -126,8 +121,7 @@ void DWARFIndex::GetFullyQualifiedType( bool DWARFIndex::GetFullyQualifiedTypeImpl( const DWARFDeclContext &context, DWARFDIE die, llvm::function_ref<bool(DWARFDIE die)> callback) { - DWARFDeclContext dwarf_decl_ctx = - die.GetDIE()->GetDWARFDeclContext(die.GetCU()); + DWARFDeclContext dwarf_decl_ctx = die.GetDWARFDeclContext(); if (dwarf_decl_ctx == context) return callback(die); return true; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h index 0551b07100a9..cb3ae8a06d78 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFIndex.h @@ -81,11 +81,10 @@ protected: StatsDuration m_index_time; /// Helper function implementing common logic for processing function dies. If - /// the function given by "ref" matches search criteria given by - /// "parent_decl_ctx" and "name_type_mask", it is inserted into the "dies" - /// vector. - bool ProcessFunctionDIE(const Module::LookupInfo &lookup_info, DIERef ref, - SymbolFileDWARF &dwarf, + /// the function given by "die" matches search criteria given by + /// "parent_decl_ctx" and "name_type_mask", it calls the callback with the + /// given die. + bool ProcessFunctionDIE(const Module::LookupInfo &lookup_info, DWARFDIE die, const CompilerDeclContext &parent_decl_ctx, llvm::function_ref<bool(DWARFDIE die)> callback); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h index 7b58c632c6c5..8c1f932d8c7f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFTypeUnit.h @@ -24,15 +24,15 @@ public: void Dump(Stream *s) const override; - uint64_t GetTypeHash() { return m_header.GetTypeHash(); } + uint64_t GetTypeHash() { return m_header.getTypeHash(); } - dw_offset_t GetTypeOffset() { return GetOffset() + m_header.GetTypeOffset(); } + dw_offset_t GetTypeOffset() { return GetOffset() + m_header.getTypeOffset(); } static bool classof(const DWARFUnit *unit) { return unit->IsTypeUnit(); } private: DWARFTypeUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, - const DWARFUnitHeader &header, + const llvm::DWARFUnitHeader &header, const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : DWARFUnit(dwarf, uid, header, abbrevs, section, is_dwo) {} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 7a40361cdede..66a762bf9b68 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -33,12 +33,12 @@ using namespace lldb_private::plugin::dwarf; extern int g_verbose; DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, - const DWARFUnitHeader &header, + const llvm::DWARFUnitHeader &header, const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo), - m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.GetDWOId()) {} + m_has_parsed_non_skeleton_unit(false), m_dwo_id(header.getDWOId()) {} DWARFUnit::~DWARFUnit() = default; @@ -63,7 +63,7 @@ void DWARFUnit::ExtractUnitDIENoDwoIfNeeded() { // parse const DWARFDataExtractor &data = GetData(); if (offset < GetNextUnitOffset() && - m_first_die.Extract(data, this, &offset)) { + m_first_die.Extract(data, *this, &offset)) { AddUnitDIE(m_first_die); return; } @@ -97,7 +97,12 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() { *m_dwo_id, m_first_die.GetOffset())); return; // Can't fetch the compile unit from the dwo file. } - dwo_cu->SetUserData(this); + // If the skeleton compile unit gets its unit DIE parsed first, then this + // will fill in the DWO file's back pointer to this skeleton compile unit. + // If the DWO files get parsed on their own first the skeleton back link + // can be done manually in DWARFUnit::GetSkeletonCompileUnit() which will + // do a reverse lookup and cache the result. + dwo_cu->SetSkeletonUnit(this); DWARFBaseDIE dwo_cu_die = dwo_cu->GetUnitDIEOnly(); if (!dwo_cu_die.IsValid()) { @@ -237,7 +242,7 @@ void DWARFUnit::ExtractDIEsRWLocked() { die_index_stack.reserve(32); die_index_stack.push_back(0); bool prev_die_had_children = false; - while (offset < next_cu_offset && die.Extract(data, this, &offset)) { + while (offset < next_cu_offset && die.Extract(data, *this, &offset)) { const bool null_die = die.IsNULL(); if (depth == 0) { assert(m_die_array.empty() && "Compile unit DIE already added"); @@ -340,7 +345,7 @@ void DWARFUnit::ExtractDIEsRWLocked() { void DWARFUnit::SetDwoStrOffsetsBase() { lldb::offset_t baseOffset = 0; - if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { if (const auto *contribution = entry->getContribution(llvm::DW_SECT_STR_OFFSETS)) baseOffset = contribution->getOffset(); @@ -484,7 +489,7 @@ ParseListTableHeader(const llvm::DWARFDataExtractor &data, uint64_t offset, void DWARFUnit::SetLoclistsBase(dw_addr_t loclists_base) { uint64_t offset = 0; - if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { const auto *contribution = entry->getContribution(llvm::DW_SECT_LOCLISTS); if (!contribution) { GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( @@ -528,7 +533,7 @@ DWARFDataExtractor DWARFUnit::GetLocationData() const { DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); const DWARFDataExtractor &data = GetVersion() >= 5 ? Ctx.getOrLoadLocListsData() : Ctx.getOrLoadLocData(); - if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { if (const auto *contribution = entry->getContribution( GetVersion() >= 5 ? llvm::DW_SECT_LOCLISTS : llvm::DW_SECT_EXT_LOC)) return DWARFDataExtractor(data, contribution->getOffset(), @@ -541,7 +546,7 @@ DWARFDataExtractor DWARFUnit::GetLocationData() const { DWARFDataExtractor DWARFUnit::GetRnglistData() const { DWARFContext &Ctx = GetSymbolFileDWARF().GetDWARFContext(); const DWARFDataExtractor &data = Ctx.getOrLoadRngListsData(); - if (const llvm::DWARFUnitIndex::Entry *entry = m_header.GetIndexEntry()) { + if (const llvm::DWARFUnitIndex::Entry *entry = m_header.getIndexEntry()) { if (const auto *contribution = entry->getContribution(llvm::DW_SECT_RNGLISTS)) return DWARFDataExtractor(data, contribution->getOffset(), @@ -665,7 +670,7 @@ DWARFUnit::GetDIE(dw_offset_t die_offset) { llvm::StringRef DWARFUnit::PeekDIEName(dw_offset_t die_offset) { DWARFDebugInfoEntry die; - if (!die.Extract(GetData(), this, &die_offset)) + if (!die.Extract(GetData(), *this, &die_offset)) return llvm::StringRef(); // Does die contain a DW_AT_Name? @@ -702,9 +707,25 @@ uint8_t DWARFUnit::GetAddressByteSize(const DWARFUnit *cu) { uint8_t DWARFUnit::GetDefaultAddressSize() { return 4; } -void *DWARFUnit::GetUserData() const { return m_user_data; } +DWARFCompileUnit *DWARFUnit::GetSkeletonUnit() { + if (m_skeleton_unit == nullptr && IsDWOUnit()) { + SymbolFileDWARFDwo *dwo = + llvm::dyn_cast_or_null<SymbolFileDWARFDwo>(&GetSymbolFileDWARF()); + // Do a reverse lookup if the skeleton compile unit wasn't set. + if (dwo) + m_skeleton_unit = dwo->GetBaseSymbolFile().GetSkeletonUnit(this); + } + return llvm::dyn_cast_or_null<DWARFCompileUnit>(m_skeleton_unit); +} -void DWARFUnit::SetUserData(void *d) { m_user_data = d; } +void DWARFUnit::SetSkeletonUnit(DWARFUnit *skeleton_unit) { + // If someone is re-setting the skeleton compile unit backlink, make sure + // it is setting it to a valid value when it wasn't valid, or if the + // value in m_skeleton_unit was valid, it should be the same value. + assert(skeleton_unit); + assert(m_skeleton_unit == nullptr || m_skeleton_unit == skeleton_unit); + m_skeleton_unit = skeleton_unit; +} bool DWARFUnit::Supports_DW_AT_APPLE_objc_complete_type() { return GetProducer() != eProducerLLVMGCC; @@ -875,8 +896,9 @@ void DWARFUnit::ComputeAbsolutePath() { m_file_spec->MakeAbsolute(GetCompilationDirectory()); } -SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile() { - ExtractUnitDIEIfNeeded(); +SymbolFileDWARFDwo *DWARFUnit::GetDwoSymbolFile(bool load_all_debug_info) { + if (load_all_debug_info) + ExtractUnitDIEIfNeeded(); if (m_dwo) return &llvm::cast<SymbolFileDWARFDwo>(m_dwo->GetSymbolFileDWARF()); return nullptr; @@ -902,84 +924,6 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { return *m_func_aranges_up; } -llvm::Error DWARFUnitHeader::ApplyIndexEntry( - const llvm::DWARFUnitIndex::Entry *index_entry) { - // We should only be calling this function when the index entry is not set and - // we have a valid one to set it to. - assert(index_entry); - assert(!m_index_entry); - - if (m_abbr_offset) - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "Package unit with a non-zero abbreviation offset"); - - auto *unit_contrib = index_entry->getContribution(); - if (!unit_contrib || unit_contrib->getLength32() != m_length + 4) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Inconsistent DWARF package unit index"); - - auto *abbr_entry = index_entry->getContribution(llvm::DW_SECT_ABBREV); - if (!abbr_entry) - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "DWARF package index missing abbreviation column"); - - m_abbr_offset = abbr_entry->getOffset(); - m_index_entry = index_entry; - return llvm::Error::success(); -} - -llvm::Expected<DWARFUnitHeader> -DWARFUnitHeader::extract(const DWARFDataExtractor &data, - DIERef::Section section, DWARFContext &context, - lldb::offset_t *offset_ptr) { - DWARFUnitHeader header; - header.m_offset = *offset_ptr; - header.m_length = data.GetDWARFInitialLength(offset_ptr); - header.m_version = data.GetU16(offset_ptr); - if (header.m_version == 5) { - header.m_unit_type = data.GetU8(offset_ptr); - header.m_addr_size = data.GetU8(offset_ptr); - header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); - if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton || - header.m_unit_type == llvm::dwarf::DW_UT_split_compile) - header.m_dwo_id = data.GetU64(offset_ptr); - } else { - header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); - header.m_addr_size = data.GetU8(offset_ptr); - header.m_unit_type = - section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile; - } - - if (header.IsTypeUnit()) { - header.m_type_hash = data.GetU64(offset_ptr); - header.m_type_offset = data.GetDWARFOffset(offset_ptr); - } - - bool length_OK = data.ValidOffset(header.GetNextUnitOffset() - 1); - bool version_OK = SymbolFileDWARF::SupportedVersion(header.m_version); - bool addr_size_OK = (header.m_addr_size == 2) || (header.m_addr_size == 4) || - (header.m_addr_size == 8); - bool type_offset_OK = - !header.IsTypeUnit() || (header.m_type_offset <= header.GetLength()); - - if (!length_OK) - return llvm::make_error<llvm::object::GenericBinaryError>( - "Invalid unit length"); - if (!version_OK) - return llvm::make_error<llvm::object::GenericBinaryError>( - "Unsupported unit version"); - if (!addr_size_OK) - return llvm::make_error<llvm::object::GenericBinaryError>( - "Invalid unit address size"); - if (!type_offset_OK) - return llvm::make_error<llvm::object::GenericBinaryError>( - "Type offset out of range"); - - return header; -} - llvm::Expected<DWARFUnitSP> DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, @@ -987,26 +931,35 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, assert(debug_info.ValidOffset(*offset_ptr)); DWARFContext &context = dwarf.GetDWARFContext(); - auto expected_header = - DWARFUnitHeader::extract(debug_info, section, context, offset_ptr); - if (!expected_header) - return expected_header.takeError(); + + // FIXME: Either properly map between DIERef::Section and + // llvm::DWARFSectionKind or switch to llvm's definition entirely. + llvm::DWARFSectionKind section_kind_llvm = + section == DIERef::Section::DebugInfo + ? llvm::DWARFSectionKind::DW_SECT_INFO + : llvm::DWARFSectionKind::DW_SECT_EXT_TYPES; + + llvm::DWARFDataExtractor debug_info_llvm = debug_info.GetAsLLVMDWARF(); + llvm::DWARFUnitHeader header; + if (llvm::Error extract_err = header.extract( + context.GetAsLLVM(), debug_info_llvm, offset_ptr, section_kind_llvm)) + return std::move(extract_err); if (context.isDwo()) { const llvm::DWARFUnitIndex::Entry *entry = nullptr; - const llvm::DWARFUnitIndex &index = expected_header->IsTypeUnit() + const llvm::DWARFUnitIndex &index = header.isTypeUnit() ? context.GetAsLLVM().getTUIndex() : context.GetAsLLVM().getCUIndex(); if (index) { - if (expected_header->IsTypeUnit()) - entry = index.getFromHash(expected_header->GetTypeHash()); - else if (auto dwo_id = expected_header->GetDWOId()) + if (header.isTypeUnit()) + entry = index.getFromHash(header.getTypeHash()); + else if (auto dwo_id = header.getDWOId()) entry = index.getFromHash(*dwo_id); } if (!entry) - entry = index.getFromOffset(expected_header->GetOffset()); + entry = index.getFromOffset(header.getOffset()); if (entry) - if (llvm::Error err = expected_header->ApplyIndexEntry(entry)) + if (llvm::Error err = header.applyIndexEntry(entry)) return std::move(err); } @@ -1017,13 +970,13 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, bool abbr_offset_OK = dwarf.GetDWARFContext().getOrLoadAbbrevData().ValidOffset( - expected_header->GetAbbrOffset()); + header.getAbbrOffset()); if (!abbr_offset_OK) return llvm::make_error<llvm::object::GenericBinaryError>( "Abbreviation offset for unit is not valid"); llvm::Expected<const llvm::DWARFAbbreviationDeclarationSet *> abbrevs_or_err = - abbr->getAbbreviationDeclarationSet(expected_header->GetAbbrOffset()); + abbr->getAbbreviationDeclarationSet(header.getAbbrOffset()); if (!abbrevs_or_err) return abbrevs_or_err.takeError(); @@ -1033,11 +986,11 @@ DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, "No abbrev exists at the specified offset."); bool is_dwo = dwarf.GetDWARFContext().isDwo(); - if (expected_header->IsTypeUnit()) - return DWARFUnitSP(new DWARFTypeUnit(dwarf, uid, *expected_header, *abbrevs, - section, is_dwo)); - return DWARFUnitSP(new DWARFCompileUnit(dwarf, uid, *expected_header, - *abbrevs, section, is_dwo)); + if (header.isTypeUnit()) + return DWARFUnitSP( + new DWARFTypeUnit(dwarf, uid, header, *abbrevs, section, is_dwo)); + return DWARFUnitSP( + new DWARFCompileUnit(dwarf, uid, header, *abbrevs, section, is_dwo)); } const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { @@ -1047,7 +1000,7 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const { } uint32_t DWARFUnit::GetHeaderByteSize() const { - switch (m_header.GetUnitType()) { + switch (m_header.getUnitType()) { case llvm::dwarf::DW_UT_compile: case llvm::dwarf::DW_UT_partial: return GetVersion() < 5 ? 11 : 12; @@ -1084,7 +1037,7 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { llvm::DWARFDataExtractor data = GetRnglistData().GetAsLLVMDWARF(); // As DW_AT_rnglists_base may be missing we need to call setAddressSize. - data.setAddressSize(m_header.GetAddressByteSize()); + data.setAddressSize(m_header.getAddressByteSize()); auto range_list_or_error = GetRnglistTable()->findList(data, offset); if (!range_list_or_error) return range_list_or_error.takeError(); @@ -1109,6 +1062,7 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { ranges.Append(DWARFRangeList::Entry(llvm_range.LowPC, llvm_range.HighPC - llvm_range.LowPC)); } + ranges.Sort(); return ranges; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index bc225a52e1d0..85c37971ced8 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -38,54 +38,6 @@ enum DWARFProducer { eProducerOther }; -/// Base class describing the header of any kind of "unit." Some information -/// is specific to certain unit types. We separate this class out so we can -/// parse the header before deciding what specific kind of unit to construct. -class DWARFUnitHeader { - dw_offset_t m_offset = 0; - dw_offset_t m_length = 0; - uint16_t m_version = 0; - dw_offset_t m_abbr_offset = 0; - - const llvm::DWARFUnitIndex::Entry *m_index_entry = nullptr; - - uint8_t m_unit_type = 0; - uint8_t m_addr_size = 0; - - uint64_t m_type_hash = 0; - uint32_t m_type_offset = 0; - - std::optional<uint64_t> m_dwo_id; - - DWARFUnitHeader() = default; - -public: - dw_offset_t GetOffset() const { return m_offset; } - uint16_t GetVersion() const { return m_version; } - uint16_t GetAddressByteSize() const { return m_addr_size; } - dw_offset_t GetLength() const { return m_length; } - dw_offset_t GetAbbrOffset() const { return m_abbr_offset; } - uint8_t GetUnitType() const { return m_unit_type; } - const llvm::DWARFUnitIndex::Entry *GetIndexEntry() const { - return m_index_entry; - } - uint64_t GetTypeHash() const { return m_type_hash; } - dw_offset_t GetTypeOffset() const { return m_type_offset; } - std::optional<uint64_t> GetDWOId() const { return m_dwo_id; } - bool IsTypeUnit() const { - return m_unit_type == llvm::dwarf::DW_UT_type || - m_unit_type == llvm::dwarf::DW_UT_split_type; - } - dw_offset_t GetNextUnitOffset() const { return m_offset + m_length + 4; } - - llvm::Error ApplyIndexEntry(const llvm::DWARFUnitIndex::Entry *index_entry); - - static llvm::Expected<DWARFUnitHeader> extract(const DWARFDataExtractor &data, - DIERef::Section section, - DWARFContext &dwarf_context, - lldb::offset_t *offset_ptr); -}; - class DWARFUnit : public UserID { using die_iterator_range = llvm::iterator_range<DWARFDebugInfoEntry::collection::iterator>; @@ -98,8 +50,14 @@ public: virtual ~DWARFUnit(); bool IsDWOUnit() { return m_is_dwo; } + /// Get the DWO ID from the DWARFUnitHeader for DWARF5, or from the unit DIE's + /// DW_AT_dwo_id or DW_AT_GNU_dwo_id for DWARF4 and earlier. std::optional<uint64_t> GetDWOId(); - + /// Get the DWO ID from the DWARFUnitHeader only. DWARF5 skeleton units have + /// the DWO ID in the compile unit header and we sometimes only want to access + /// this cheap value without causing the more expensive attribute fetches that + /// GetDWOId() uses. + std::optional<uint64_t> GetHeaderDWOId() { return m_header.getDWOId(); } void ExtractUnitDIEIfNeeded(); void ExtractUnitDIENoDwoIfNeeded(); void ExtractDIEsIfNeeded(); @@ -137,7 +95,7 @@ public: uint32_t GetHeaderByteSize() const; // Offset of the initial length field. - dw_offset_t GetOffset() const { return m_header.GetOffset(); } + dw_offset_t GetOffset() const { return m_header.getOffset(); } /// Get the size in bytes of the length field in the header. /// /// In DWARF32 this is just 4 bytes @@ -153,15 +111,15 @@ public: dw_offset_t GetFirstDIEOffset() const { return GetOffset() + GetHeaderByteSize(); } - dw_offset_t GetNextUnitOffset() const { return m_header.GetNextUnitOffset(); } + dw_offset_t GetNextUnitOffset() const { return m_header.getNextUnitOffset(); } // Size of the CU data (without initial length and without header). size_t GetDebugInfoSize() const; // Size of the CU data incl. header but without initial length. - dw_offset_t GetLength() const { return m_header.GetLength(); } - uint16_t GetVersion() const { return m_header.GetVersion(); } + dw_offset_t GetLength() const { return m_header.getLength(); } + uint16_t GetVersion() const { return m_header.getVersion(); } const llvm::DWARFAbbreviationDeclarationSet *GetAbbreviations() const; dw_offset_t GetAbbrevOffset() const; - uint8_t GetAddressByteSize() const { return m_header.GetAddressByteSize(); } + uint8_t GetAddressByteSize() const { return m_header.getAddressByteSize(); } dw_addr_t GetAddrBase() const { return m_addr_base.value_or(0); } dw_addr_t GetBaseAddress() const { return m_base_addr; } dw_offset_t GetLineTableOffset(); @@ -198,9 +156,21 @@ public: static uint8_t GetDefaultAddressSize(); - void *GetUserData() const; + lldb_private::CompileUnit *GetLLDBCompUnit() const { return m_lldb_cu; } + + void SetLLDBCompUnit(lldb_private::CompileUnit *cu) { m_lldb_cu = cu; } + + /// Get the skeleton compile unit for a DWO file. + /// + /// We need to keep track of the skeleton compile unit for a DWO file so + /// we can access it. Sometimes this value is cached when the skeleton + /// compile unit is first parsed, but if a .dwp file parses all of the + /// DWARFUnits in the file, the skeleton compile unit might not have been + /// parsed yet, to there might not be a backlink. This accessor handles + /// both cases correctly and avoids crashes. + DWARFCompileUnit *GetSkeletonUnit(); - void SetUserData(void *d); + void SetSkeletonUnit(DWARFUnit *skeleton_unit); bool Supports_DW_AT_APPLE_objc_complete_type(); @@ -223,7 +193,7 @@ public: FileSpec GetFile(size_t file_idx); FileSpec::Style GetPathStyle(); - SymbolFileDWARFDwo *GetDwoSymbolFile(); + SymbolFileDWARFDwo *GetDwoSymbolFile(bool load_all_debug_info = true); die_iterator_range dies() { ExtractDIEsIfNeeded(); @@ -232,8 +202,8 @@ public: DIERef::Section GetDebugSection() const { return m_section; } - uint8_t GetUnitType() const { return m_header.GetUnitType(); } - bool IsTypeUnit() const { return m_header.IsTypeUnit(); } + uint8_t GetUnitType() const { return m_header.getUnitType(); } + bool IsTypeUnit() const { return m_header.isTypeUnit(); } /// Note that this check only works for DWARF5+. bool IsSkeletonUnit() const { return GetUnitType() == llvm::dwarf::DW_UT_skeleton; @@ -302,7 +272,7 @@ public: protected: DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, - const DWARFUnitHeader &header, + const llvm::DWARFUnitHeader &header, const llvm::DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo); @@ -334,9 +304,11 @@ protected: SymbolFileDWARF &m_dwarf; std::shared_ptr<DWARFUnit> m_dwo; - DWARFUnitHeader m_header; + llvm::DWARFUnitHeader m_header; const llvm::DWARFAbbreviationDeclarationSet *m_abbrevs = nullptr; - void *m_user_data = nullptr; + lldb_private::CompileUnit *m_lldb_cu = nullptr; + // If this is a DWO file, we have a backlink to our skeleton compile unit. + DWARFUnit *m_skeleton_unit = nullptr; // The compile unit debug information entry item DWARFDebugInfoEntry::collection m_die_array; mutable llvm::sys::RWMutex m_die_array_mutex; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp index b718f98340a7..7e66b3dccf97 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp @@ -9,10 +9,12 @@ #include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h" +#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "lldb/Core/Module.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" +#include "llvm/ADT/Sequence.h" #include <optional> using namespace lldb_private; @@ -33,6 +35,17 @@ DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names, module, std::move(index_up), debug_names, debug_str, dwarf)); } +llvm::DenseSet<uint64_t> +DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) { + llvm::DenseSet<uint64_t> result; + for (const DebugNames::NameIndex &ni : debug_names) { + const uint32_t num_tus = ni.getForeignTUCount(); + for (uint32_t tu = 0; tu < num_tus; ++tu) + result.insert(ni.getForeignTUSignature(tu)); + } + return result; +} + llvm::DenseSet<dw_offset_t> DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { llvm::DenseSet<dw_offset_t> result; @@ -47,41 +60,108 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) { return result; } -std::optional<DIERef> -DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) const { +std::optional<DWARFTypeUnit *> +DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const { + std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature(); + if (!type_sig.has_value()) + return std::nullopt; + + // Ask the entry for the skeleton compile unit offset and fetch the .dwo + // file from it and get the type unit by signature from there. If we find + // the type unit in the .dwo file, we don't need to check that the + // DW_AT_dwo_name matches because each .dwo file can have its own type unit. + std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset(); + if (!cu_offset) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + + DWARFUnit *cu = + m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset); + if (!cu) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + + auto dwp_sp = m_debug_info.GetDwpSymbolFile(); + if (!dwp_sp) { + // No .dwp file, we need to load the .dwo file. + DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit(); + // We don't need the check if the type unit matches the .dwo file if we have + // a .dwo file (not a .dwp), so we can just return the value here. + if (!dwo_cu.IsDWOUnit()) + return nullptr; // We weren't able to load the .dwo file. + return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash( + *type_sig); + } + // We have a .dwp file, just get the type unit from there. We need to verify + // that the type unit that ended up in the final .dwp file is the right type + // unit. Type units have signatures which are the same across multiple .dwo + // files, but only one of those type units will end up in the .dwp file. The + // contents of type units for the same type can be different in different .dwo + // files, which means the DIE offsets might not be the same between two + // different type units. So we need to determine if this accelerator table + // matches the type unit that ended up in the .dwp file. If it doesn't match, + // then we need to ignore this accelerator table entry as the type unit that + // is in the .dwp file will have its own index. In order to determine if the + // type unit that ended up in a .dwp file matches this DebugNames::Entry, we + // need to find the skeleton compile unit for this entry. + DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig); + if (!foreign_tu) + return nullptr; // Return NULL, this is a type unit, but couldn't find it. + + DWARFBaseDIE cu_die = cu->GetUnitDIEOnly(); + DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly(); + llvm::StringRef cu_dwo_name = + cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + llvm::StringRef tu_dwo_name = + tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr); + if (cu_dwo_name == tu_dwo_name) + return foreign_tu; // We found a match! + return nullptr; // Return NULL, this is a type unit, but couldn't find it. +} + +DWARFUnit * +DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const { + + if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry)) + return foreign_tu.value(); + // Look for a DWARF unit offset (CU offset or local TU offset) as they are // both offsets into the .debug_info section. std::optional<uint64_t> unit_offset = entry.getCUOffset(); - if (!unit_offset) { + if (!unit_offset) unit_offset = entry.getLocalTUOffset(); - if (!unit_offset) - return std::nullopt; + if (unit_offset) { + if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, + *unit_offset)) + return &cu->GetNonSkeletonUnit(); } + return nullptr; +} - DWARFUnit *cu = - m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset); - if (!cu) - return std::nullopt; - - cu = &cu->GetNonSkeletonUnit(); - if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset()) - return DIERef(cu->GetSymbolFileDWARF().GetFileIndex(), - DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset); - - return std::nullopt; +DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const { + DWARFUnit *unit = GetNonSkeletonUnit(entry); + std::optional<uint64_t> die_offset = entry.getDIEUnitOffset(); + if (!unit || !die_offset) + return DWARFDIE(); + if (DWARFDIE die = unit->GetDIE(unit->GetOffset() + *die_offset)) + return die; + + m_module.ReportErrorIfModifyDetected( + "the DWARF debug information has been modified (bad offset {0:x} in " + "debug_names section)\n", + *die_offset); + return DWARFDIE(); } bool DebugNamesDWARFIndex::ProcessEntry( const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback) { - std::optional<DIERef> ref = ToDIERef(entry); - if (!ref) - return true; - SymbolFileDWARF &dwarf = *llvm::cast<SymbolFileDWARF>( - m_module.GetSymbolFile()->GetBackingSymbolFile()); - DWARFDIE die = dwarf.GetDIE(*ref); + DWARFDIE die = GetDIE(entry); if (!die) return true; + // Clang used to erroneously emit index entries for declaration DIEs in case + // when the definition is in a type unit (llvm.org/pr77696). + if (die.IsStructUnionOrClass() && + die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) + return true; return callback(die); } @@ -178,7 +258,7 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass( llvm::function_ref<bool(DWARFDIE die)> callback) { // Keep a list of incomplete types as fallback for when we don't find the // complete type. - DIEArray incomplete_types; + std::vector<DWARFDIE> incomplete_types; for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(class_name.GetStringRef())) { @@ -186,19 +266,14 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass( entry.tag() != DW_TAG_class_type) continue; - std::optional<DIERef> ref = ToDIERef(entry); - if (!ref) - continue; - - DWARFUnit *cu = m_debug_info.GetUnit(*ref); - if (!cu || !cu->Supports_DW_AT_APPLE_objc_complete_type()) { - incomplete_types.push_back(*ref); + DWARFDIE die = GetDIE(entry); + if (!die) { + // Report invalid continue; } - - DWARFDIE die = m_debug_info.GetDIE(*ref); - if (!die) { - ReportInvalidDIERef(*ref, class_name.GetStringRef()); + DWARFUnit *cu = die.GetCU(); + if (!cu->Supports_DW_AT_APPLE_objc_complete_type()) { + incomplete_types.push_back(die); continue; } @@ -207,17 +282,125 @@ void DebugNamesDWARFIndex::GetCompleteObjCClass( callback(die); return; } - incomplete_types.push_back(*ref); + incomplete_types.push_back(die); } - auto dierefcallback = DIERefCallback(callback, class_name.GetStringRef()); - for (DIERef ref : incomplete_types) - if (!dierefcallback(ref)) + for (DWARFDIE die : incomplete_types) + if (!callback(die)) return; m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback); } +namespace { +using Entry = llvm::DWARFDebugNames::Entry; + +/// If `entry` and all of its parents have an `IDX_parent`, use that information +/// to build and return a list of at most `max_parents` parent Entries. +/// `entry` itself is not included in the list. +/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted, +/// nullopt is returned. +std::optional<llvm::SmallVector<Entry, 4>> +getParentChain(Entry entry, uint32_t max_parents) { + llvm::SmallVector<Entry, 4> parent_entries; + + do { + if (!entry.hasParentInformation()) + return std::nullopt; + + llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry(); + if (!parent) { + // Bad data. + LLDB_LOG_ERROR( + GetLog(DWARFLog::Lookups), parent.takeError(), + "Failed to extract parent entry from a non-empty IDX_parent"); + return std::nullopt; + } + + // Last parent in the chain. + if (!parent->has_value()) + break; + + parent_entries.push_back(**parent); + entry = **parent; + } while (parent_entries.size() < max_parents); + + return parent_entries; +} +} // namespace + +void DebugNamesDWARFIndex::GetFullyQualifiedType( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) { + if (context.GetSize() == 0) + return; + + llvm::StringRef leaf_name = context[0].name; + llvm::SmallVector<llvm::StringRef> parent_names; + for (auto idx : llvm::seq<int>(1, context.GetSize())) + parent_names.emplace_back(context[idx].name); + + // For each entry, grab its parent chain and check if we have a match. + for (const DebugNames::Entry &entry : + m_debug_names_up->equal_range(leaf_name)) { + if (!isType(entry.tag())) + continue; + + // If we get a NULL foreign_tu back, the entry doesn't match the type unit + // in the .dwp file, or we were not able to load the .dwo file or the DWO ID + // didn't match. + std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry); + if (foreign_tu && foreign_tu.value() == nullptr) + continue; + + // Grab at most one extra parent, subsequent parents are not necessary to + // test equality. + std::optional<llvm::SmallVector<Entry, 4>> parent_chain = + getParentChain(entry, parent_names.size() + 1); + + if (!parent_chain) { + // Fallback: use the base class implementation. + if (!ProcessEntry(entry, [&](DWARFDIE die) { + return GetFullyQualifiedTypeImpl(context, die, callback); + })) + return; + continue; + } + + if (SameParentChain(parent_names, *parent_chain) && + !ProcessEntry(entry, callback)) + return; + } +} + +bool DebugNamesDWARFIndex::SameParentChain( + llvm::ArrayRef<llvm::StringRef> parent_names, + llvm::ArrayRef<DebugNames::Entry> parent_entries) const { + + if (parent_entries.size() != parent_names.size()) + return false; + + auto SameAsEntryATName = [this](llvm::StringRef name, + const DebugNames::Entry &entry) { + // Peek at the AT_name of `entry` and test equality to `name`. + auto maybe_dieoffset = entry.getDIEUnitOffset(); + if (!maybe_dieoffset) + return false; + DWARFUnit *unit = GetNonSkeletonUnit(entry); + if (!unit) + return false; + return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset); + }; + + // If the AT_name of any parent fails to match the expected name, we don't + // have a match. + for (auto [parent_name, parent_entry] : + llvm::zip_equal(parent_names, parent_entries)) + if (!SameAsEntryATName(parent_name, parent_entry)) + return false; + return true; +} + void DebugNamesDWARFIndex::GetTypes( ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) { for (const DebugNames::Entry &entry : @@ -272,8 +455,8 @@ void DebugNamesDWARFIndex::GetFunctions( if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine) continue; - if (std::optional<DIERef> ref = ToDIERef(entry)) { - if (!ProcessFunctionDIE(lookup_info, *ref, dwarf, parent_decl_ctx, + if (DWARFDIE die = GetDIE(entry)) { + if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx, [&](DWARFDIE die) { if (!seen.insert(die.GetDIE()).second) return true; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h index cca0913c4124..cb15c1d4f994 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h @@ -10,7 +10,6 @@ #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DEBUGNAMESDWARFINDEX_H #include "Plugins/SymbolFile/DWARF/DWARFIndex.h" -#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "lldb/Utility/ConstString.h" @@ -42,6 +41,11 @@ public: void GetCompleteObjCClass( ConstString class_name, bool must_be_implementation, llvm::function_ref<bool(DWARFDIE die)> callback) override; + + /// Uses DWARF5's IDX_parent fields, when available, to speed up this query. + void GetFullyQualifiedType( + const DWARFDeclContext &context, + llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetTypes(ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) override; void GetTypes(const DWARFDeclContext &context, @@ -66,7 +70,8 @@ private: : DWARFIndex(module), m_debug_info(dwarf.DebugInfo()), m_debug_names_data(debug_names_data), m_debug_str_data(debug_str_data), m_debug_names_up(std::move(debug_names_up)), - m_fallback(module, dwarf, GetUnits(*m_debug_names_up)) {} + m_fallback(module, dwarf, GetUnits(*m_debug_names_up), + GetTypeUnitSignatures(*m_debug_names_up)) {} DWARFDebugInfo &m_debug_info; @@ -79,15 +84,47 @@ private: std::unique_ptr<DebugNames> m_debug_names_up; ManualDWARFIndex m_fallback; - std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const; + DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const; + DWARFDIE GetDIE(const DebugNames::Entry &entry) const; + + /// Checks if an entry is a foreign TU and fetch the type unit. + /// + /// This function checks if the DebugNames::Entry refers to a foreign TU and + /// returns an optional with a value of the \a entry is a foreign type unit + /// entry. A valid pointer will be returned if this entry is from a .dwo file + /// or if it is from a .dwp file and it matches the type unit's originating + /// .dwo file by verifying that the DW_TAG_type_unit DIE has a DW_AT_dwo_name + /// that matches the DWO name from the originating skeleton compile unit. + /// + /// \param[in] entry + /// The accelerator table entry to check. + /// + /// \returns + /// A std::optional that has a value if this entry represents a foreign type + /// unit. If the pointer is valid, then we were able to find and match the + /// entry to the type unit in the .dwo or .dwp file. The returned value can + /// have a valid, yet contain NULL in the following cases: + /// - we were not able to load the .dwo file (missing or DWO ID mismatch) + /// - we were able to load the .dwp file, but the type units DWO name + /// doesn't match the originating skeleton compile unit's entry + /// Returns std::nullopt if this entry is not a foreign type unit entry. + std::optional<DWARFTypeUnit *> + GetForeignTypeUnit(const DebugNames::Entry &entry) const; + bool ProcessEntry(const DebugNames::Entry &entry, llvm::function_ref<bool(DWARFDIE die)> callback); + /// Returns true if `parent_entries` have identical names to `parent_names`. + bool SameParentChain(llvm::ArrayRef<llvm::StringRef> parent_names, + llvm::ArrayRef<DebugNames::Entry> parent_entries) const; + static void MaybeLogLookupError(llvm::Error error, const DebugNames::NameIndex &ni, llvm::StringRef name); static llvm::DenseSet<dw_offset_t> GetUnits(const DebugNames &debug_names); + static llvm::DenseSet<uint64_t> + GetTypeUnitSignatures(const DebugNames &debug_names); }; } // namespace dwarf diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp index 6b063f3bd88d..795355b57a06 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp @@ -22,6 +22,7 @@ static constexpr Log::Category g_categories[] = { {{"map"}, {"log insertions of object files into DWARF debug maps"}, DWARFLog::DebugMap}, + {{"split"}, {"log split DWARF related activities"}, DWARFLog::SplitDwarf}, }; static Log::Channel g_channel(g_categories, DWARFLog::DebugInfo); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h index 662aa6757e2f..7f254a1162bd 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h @@ -20,6 +20,7 @@ enum class DWARFLog : Log::MaskType { DebugMap = Log::ChannelFlag<2>, Lookups = Log::ChannelFlag<3>, TypeCompletion = Log::ChannelFlag<4>, + SplitDwarf = Log::ChannelFlag<5>, LLVM_MARK_AS_BITMASK_ENUM(TypeCompletion) }; LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 92275600f99c..d581d3773ab2 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -60,8 +60,11 @@ void ManualDWARFIndex::Index() { } if (dwp_info && dwp_info->ContainsTypeUnits()) { for (size_t U = 0; U < dwp_info->GetNumUnits(); ++U) { - if (auto *tu = llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) - units_to_index.push_back(tu); + if (auto *tu = + llvm::dyn_cast<DWARFTypeUnit>(dwp_info->GetUnitAtIndex(U))) { + if (!m_type_sigs_to_avoid.contains(tu->GetTypeHash())) + units_to_index.push_back(tu); + } } } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index 0126e587e52d..d8c4a22ab21f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -21,9 +21,11 @@ class SymbolFileDWARFDwo; class ManualDWARFIndex : public DWARFIndex { public: ManualDWARFIndex(Module &module, SymbolFileDWARF &dwarf, - llvm::DenseSet<dw_offset_t> units_to_avoid = {}) + llvm::DenseSet<dw_offset_t> units_to_avoid = {}, + llvm::DenseSet<uint64_t> type_sigs_to_avoid = {}) : DWARFIndex(module), m_dwarf(&dwarf), - m_units_to_avoid(std::move(units_to_avoid)) {} + m_units_to_avoid(std::move(units_to_avoid)), + m_type_sigs_to_avoid(std::move(type_sigs_to_avoid)) {} void Preload() override { Index(); } @@ -170,6 +172,7 @@ private: SymbolFileDWARF *m_dwarf; /// Which dwarf units should we skip while building the index. llvm::DenseSet<dw_offset_t> m_units_to_avoid; + llvm::DenseSet<uint64_t> m_type_sigs_to_avoid; IndexSet m_set; bool m_indexed = false; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index fed97858c83f..7cd3a33c7de5 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -481,6 +481,13 @@ static ConstString GetDWARFMachOSegmentName() { return g_dwarf_section_name; } +llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> & +SymbolFileDWARF::GetForwardDeclCompilerTypeToDIE() { + if (SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile()) + return debug_map_symfile->GetForwardDeclCompilerTypeToDIE(); + return m_forward_decl_compiler_type_to_die; +} + UniqueDWARFASTTypeMap &SymbolFileDWARF::GetUniqueDWARFASTTypeMap() { SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); if (debug_map_symfile) @@ -693,6 +700,7 @@ llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { if (debug_abbrev_data.GetByteSize() == 0) return nullptr; + ElapsedTime elapsed(m_parse_time); auto abbr = std::make_unique<llvm::DWARFDebugAbbrev>(debug_abbrev_data.GetAsLLVM()); llvm::Error error = abbr->parse(); @@ -709,8 +717,8 @@ llvm::DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { DWARFDebugInfo &SymbolFileDWARF::DebugInfo() { llvm::call_once(m_info_once_flag, [&] { - LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); + LLDB_SCOPED_TIMER(); + m_info = std::make_unique<DWARFDebugInfo>(*this, m_context); }); return *m_info; @@ -722,8 +730,8 @@ DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) { // The compile unit ID is the index of the DWARF unit. DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID()); - if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) - dwarf_cu->SetUserData(comp_unit); + if (dwarf_cu && dwarf_cu->GetLLDBCompUnit() == nullptr) + dwarf_cu->SetLLDBCompUnit(comp_unit); // It must be DWARFCompileUnit when it created a CompileUnit. return llvm::cast_or_null<DWARFCompileUnit>(dwarf_cu); @@ -731,8 +739,7 @@ DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) { DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { if (!m_ranges) { - LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, - static_cast<void *>(this)); + LLDB_SCOPED_TIMER(); if (m_context.getOrLoadRangesData().GetByteSize() > 0) m_ranges = std::make_unique<DWARFDebugRanges>(); @@ -771,7 +778,7 @@ static const char *GetDWOName(DWARFCompileUnit &dwarf_cu, lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; - CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); + CompileUnit *comp_unit = dwarf_cu.GetLLDBCompUnit(); if (comp_unit) { // We already parsed this compile unit, had out a shared pointer to it cu_sp = comp_unit->shared_from_this(); @@ -779,7 +786,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { if (GetDebugMapSymfile()) { // Let the debug map create the compile unit cu_sp = m_debug_map_symfile->GetCompileUnit(this, dwarf_cu); - dwarf_cu.SetUserData(cu_sp.get()); + dwarf_cu.SetLLDBCompUnit(cu_sp.get()); } else { ModuleSP module_sp(m_objfile_sp->GetModule()); if (module_sp) { @@ -792,7 +799,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { *GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, eLazyBoolCalculate, std::move(support_files)); - dwarf_cu.SetUserData(cu_sp.get()); + dwarf_cu.SetLLDBCompUnit(cu_sp.get()); SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp); }; @@ -1554,8 +1561,10 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, Log *log = GetLog(DWARFLog::DebugInfo); if (log) GetObjectFile()->GetModule()->LogMessage( - log, "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) {1} '{2}'", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + log, + "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) {1} ({2}) '{3}'", + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); // We might be coming in in the middle of a type tree (a class within a // class, an enum within a class), so parse any needed parent DIEs before @@ -1571,11 +1580,10 @@ Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die, if (log) GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) " - "{1} '{2}' " - "resolve parent forward type for {3:x16})", - die.GetOffset(), die.GetTagAsCString(), die.GetName(), - decl_ctx_die.GetOffset()); + "SymbolFileDWARF::ResolveTypeUID (die = {0:x16}) {1} ({2}) " + "'{3}' resolve parent forward type for {4:x16})", + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName(), decl_ctx_die.GetOffset()); } break; default: @@ -1630,27 +1638,45 @@ bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) { return true; } - DWARFDIE dwarf_die = GetDIE(die_it->getSecond()); - if (dwarf_die) { - // Once we start resolving this type, remove it from the forward - // declaration map in case anyone child members or other types require this - // type to get resolved. The type will get resolved when all of the calls - // to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition are done. - GetForwardDeclCompilerTypeToDIE().erase(die_it); - - Type *type = GetDIEToType().lookup(dwarf_die.GetDIE()); + DWARFDIE decl_die = GetDIE(die_it->getSecond()); + // Once we start resolving this type, remove it from the forward + // declaration map in case anyone's child members or other types require this + // type to get resolved. + GetForwardDeclCompilerTypeToDIE().erase(die_it); + DWARFDIE def_die = FindDefinitionDIE(decl_die); + if (!def_die) { + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) { + // We weren't able to find a full declaration in this DWARF, see + // if we have a declaration anywhere else... + def_die = debug_map_symfile->FindDefinitionDIE(decl_die); + } + } + if (!def_die) { + // If we don't have definition DIE, CompleteTypeFromDWARF will forcefully + // complete this type. + def_die = decl_die; + } - Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion); - if (log) - GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( - log, "{0:x8}: {1} '{2}' resolving forward declaration...", - dwarf_die.GetID(), dwarf_die.GetTagAsCString(), - type->GetName().AsCString()); - assert(compiler_type); - if (DWARFASTParser *dwarf_ast = GetDWARFParser(*dwarf_die.GetCU())) - return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type); + DWARFASTParser *dwarf_ast = GetDWARFParser(*def_die.GetCU()); + if (!dwarf_ast) + return false; + Type *type = GetDIEToType().lookup(decl_die.GetDIE()); + if (decl_die != def_die) { + GetDIEToType()[def_die.GetDIE()] = type; + DWARFASTParserClang *ast_parser = + static_cast<DWARFASTParserClang *>(dwarf_ast); + ast_parser->MapDeclDIEToDefDIE(decl_die, def_die); } - return false; + + Log *log = GetLog(DWARFLog::DebugInfo | DWARFLog::TypeCompletion); + if (log) + GetObjectFile()->GetModule()->LogMessageVerboseBacktrace( + log, "{0:x8}: {1} ({2}) '{3}' resolving forward declaration...", + def_die.GetID(), DW_TAG_value_to_name(def_die.Tag()), def_die.Tag(), + type->GetName().AsCString()); + assert(compiler_type); + return dwarf_ast->CompleteTypeFromDWARF(def_die, type, compiler_type); } Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, @@ -1664,8 +1690,9 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, return type; GetObjectFile()->GetModule()->ReportError( - "Parsing a die that is being parsed die: {0:x16}: {1} {2}", - die.GetOffset(), die.GetTagAsCString(), die.GetName()); + "Parsing a die that is being parsed die: {0:x16}: {1} ({2}) {3}", + die.GetOffset(), DW_TAG_value_to_name(die.Tag()), die.Tag(), + die.GetName()); } else return type; @@ -1675,20 +1702,20 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, CompileUnit * SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu) { + if (dwarf_cu.IsDWOUnit()) { - DWARFCompileUnit *non_dwo_cu = - static_cast<DWARFCompileUnit *>(dwarf_cu.GetUserData()); + DWARFCompileUnit *non_dwo_cu = dwarf_cu.GetSkeletonUnit(); assert(non_dwo_cu); return non_dwo_cu->GetSymbolFileDWARF().GetCompUnitForDWARFCompUnit( *non_dwo_cu); } // Check if the symbol vendor already knows about this compile unit? - if (dwarf_cu.GetUserData() == nullptr) { - // The symbol vendor doesn't know about this compile unit, we need to parse - // and add it to the symbol vendor object. - return ParseCompileUnit(dwarf_cu).get(); - } - return static_cast<CompileUnit *>(dwarf_cu.GetUserData()); + CompileUnit *lldb_cu = dwarf_cu.GetLLDBCompUnit(); + if (lldb_cu) + return lldb_cu; + // The symbol vendor doesn't know about this compile unit, we need to parse + // and add it to the symbol vendor object. + return ParseCompileUnit(dwarf_cu).get(); } void SymbolFileDWARF::GetObjCMethods( @@ -1725,14 +1752,7 @@ lldb::ModuleSP SymbolFileDWARF::GetExternalModule(ConstString name) { return pos->second; } -DWARFDIE -SymbolFileDWARF::GetDIE(const DIERef &die_ref) { - // This method can be called without going through the symbol vendor so we - // need to lock the module. - std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - - SymbolFileDWARF *symbol_file = nullptr; - +SymbolFileDWARF *SymbolFileDWARF::GetDIERefSymbolFile(const DIERef &die_ref) { // Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API we // must make sure we use the correct DWARF file when resolving things. On // MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple @@ -1740,29 +1760,44 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { // references to other DWARF objects and we must be ready to receive a // "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF // instance. + std::optional<uint32_t> file_index = die_ref.file_index(); - if (file_index) { - if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) { - symbol_file = debug_map->GetSymbolFileByOSOIndex(*file_index); // OSO case - if (symbol_file) - return symbol_file->DebugInfo().GetDIE(die_ref); - return DWARFDIE(); - } + // If the file index matches, then we have the right SymbolFileDWARF already. + // This will work for both .dwo file and DWARF in .o files for mac. Also if + // both the file indexes are invalid, then we have a match. + if (GetFileIndex() == file_index) + return this; + + if (file_index) { + // We have a SymbolFileDWARFDebugMap, so let it find the right file + if (SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile()) + return debug_map->GetSymbolFileByOSOIndex(*file_index); + + // Handle the .dwp file case correctly if (*file_index == DIERef::k_file_index_mask) - symbol_file = m_dwp_symfile.get(); // DWP case - else - symbol_file = this->DebugInfo() - .GetUnitAtIndex(*die_ref.file_index()) - ->GetDwoSymbolFile(); // DWO case - } else if (die_ref.die_offset() == DW_INVALID_OFFSET) { - return DWARFDIE(); + return GetDwpSymbolFile().get(); // DWP case + + // Handle the .dwo file case correctly + return DebugInfo().GetUnitAtIndex(*die_ref.file_index()) + ->GetDwoSymbolFile(); // DWO case } + return this; +} - if (symbol_file) - return symbol_file->GetDIE(die_ref); +DWARFDIE +SymbolFileDWARF::GetDIE(const DIERef &die_ref) { + if (die_ref.die_offset() == DW_INVALID_OFFSET) + return DWARFDIE(); - return DebugInfo().GetDIE(die_ref); + // This method can be called without going through the symbol vendor so we + // need to lock the module. + std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); + SymbolFileDWARF *symbol_file = GetDIERefSymbolFile(die_ref); + if (symbol_file) + return symbol_file->DebugInfo().GetDIE(die_ref.section(), + die_ref.die_offset()); + return DWARFDIE(); } /// Return the DW_AT_(GNU_)dwo_id. @@ -1785,6 +1820,10 @@ std::optional<uint64_t> SymbolFileDWARF::GetDWOId() { return {}; } +DWARFUnit *SymbolFileDWARF::GetSkeletonUnit(DWARFUnit *dwo_unit) { + return DebugInfo().GetSkeletonUnit(dwo_unit); +} + std::shared_ptr<SymbolFileDWARFDwo> SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { @@ -2084,16 +2123,14 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { if (var_sp && !var_sp->GetLocationIsConstantValueData()) { const DWARFExpressionList &location = var_sp->LocationExpressionList(); - Value location_result; - Status error; ExecutionContext exe_ctx; - if (location.Evaluate(&exe_ctx, nullptr, LLDB_INVALID_ADDRESS, - nullptr, nullptr, location_result, - &error)) { - if (location_result.GetValueType() == + llvm::Expected<Value> location_result = location.Evaluate( + &exe_ctx, nullptr, LLDB_INVALID_ADDRESS, nullptr, nullptr); + if (location_result) { + if (location_result->GetValueType() == Value::ValueType::FileAddress) { lldb::addr_t file_addr = - location_result.GetScalar().ULongLong(); + location_result->GetScalar().ULongLong(); lldb::addr_t byte_size = 1; if (var_sp->GetType()) byte_size = @@ -2101,6 +2138,10 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { m_global_aranges_up->Append(GlobalVariableMap::Entry( file_addr, byte_size, var_sp.get())); } + } else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), + location_result.takeError(), + "location expression failed to execute: {0}"); } } } @@ -2667,6 +2708,29 @@ static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) { } return any_context_updated; } + +uint64_t SymbolFileDWARF::GetDebugInfoSize(bool load_all_debug_info) { + DWARFDebugInfo &info = DebugInfo(); + uint32_t num_comp_units = info.GetNumUnits(); + + uint64_t debug_info_size = SymbolFileCommon::GetDebugInfoSize(); + // In dwp scenario, debug info == skeleton debug info + dwp debug info. + if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile()) + return debug_info_size + dwp_sp->GetDebugInfoSize(); + + // In dwo scenario, debug info == skeleton debug info + all dwo debug info. + for (uint32_t i = 0; i < num_comp_units; i++) { + DWARFUnit *cu = info.GetUnitAtIndex(i); + if (cu == nullptr) + continue; + + SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile(load_all_debug_info); + if (dwo) + debug_info_size += dwo->GetDebugInfoSize(); + } + return debug_info_size; +} + void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) { // Make sure we haven't already searched this SymbolFile before. @@ -3006,205 +3070,120 @@ TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE( return type_sp; } -// This function helps to ensure that the declaration contexts match for two -// different DIEs. Often times debug information will refer to a forward -// declaration of a type (the equivalent of "struct my_struct;". There will -// often be a declaration of that type elsewhere that has the full definition. -// When we go looking for the full type "my_struct", we will find one or more -// matches in the accelerator tables and we will then need to make sure the -// type was in the same declaration context as the original DIE. This function -// can efficiently compare two DIEs and will return true when the declaration -// context matches, and false when they don't. -bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1, - const DWARFDIE &die2) { - if (die1 == die2) - return true; - - std::vector<DWARFDIE> decl_ctx_1; - std::vector<DWARFDIE> decl_ctx_2; - // The declaration DIE stack is a stack of the declaration context DIEs all - // the way back to the compile unit. If a type "T" is declared inside a class - // "B", and class "B" is declared inside a class "A" and class "A" is in a - // namespace "lldb", and the namespace is in a compile unit, there will be a - // stack of DIEs: - // - // [0] DW_TAG_class_type for "B" - // [1] DW_TAG_class_type for "A" - // [2] DW_TAG_namespace for "lldb" - // [3] DW_TAG_compile_unit or DW_TAG_partial_unit for the source file. - // - // We grab both contexts and make sure that everything matches all the way - // back to the compiler unit. - - // First lets grab the decl contexts for both DIEs - decl_ctx_1 = die1.GetDeclContextDIEs(); - decl_ctx_2 = die2.GetDeclContextDIEs(); - // Make sure the context arrays have the same size, otherwise we are done - const size_t count1 = decl_ctx_1.size(); - const size_t count2 = decl_ctx_2.size(); - if (count1 != count2) - return false; +DWARFDIE +SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) { + const char *name = die.GetName(); + if (!name) + return {}; + if (!die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0)) + return die; - // Make sure the DW_TAG values match all the way back up the compile unit. If - // they don't, then we are done. - DWARFDIE decl_ctx_die1; - DWARFDIE decl_ctx_die2; - size_t i; - for (i = 0; i < count1; i++) { - decl_ctx_die1 = decl_ctx_1[i]; - decl_ctx_die2 = decl_ctx_2[i]; - if (decl_ctx_die1.Tag() != decl_ctx_die2.Tag()) - return false; - } -#ifndef NDEBUG + Progress progress(llvm::formatv( + "Searching definition DIE in {0}: '{1}'", + GetObjectFile()->GetFileSpec().GetFilename().GetString(), name)); - // Make sure the top item in the decl context die array is always - // DW_TAG_compile_unit or DW_TAG_partial_unit. If it isn't then - // something went wrong in the DWARFDIE::GetDeclContextDIEs() - // function. - dw_tag_t cu_tag = decl_ctx_1[count1 - 1].Tag(); - UNUSED_IF_ASSERT_DISABLED(cu_tag); - assert(cu_tag == DW_TAG_compile_unit || cu_tag == DW_TAG_partial_unit); + const dw_tag_t tag = die.Tag(); -#endif - // Always skip the compile unit when comparing by only iterating up to "count - // - 1". Here we compare the names as we go. - for (i = 0; i < count1 - 1; i++) { - decl_ctx_die1 = decl_ctx_1[i]; - decl_ctx_die2 = decl_ctx_2[i]; - const char *name1 = decl_ctx_die1.GetName(); - const char *name2 = decl_ctx_die2.GetName(); - // If the string was from a DW_FORM_strp, then the pointer will often be - // the same! - if (name1 == name2) - continue; + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + if (log) { + GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::FindDefinitionDIE(tag={0} " + "({1}), name='{2}')", + DW_TAG_value_to_name(tag), tag, name); + } - // Name pointers are not equal, so only compare the strings if both are not - // NULL. - if (name1 && name2) { - // If the strings don't compare, we are done... - if (strcmp(name1, name2) != 0) - return false; + // Get the type system that we are looking to find a type for. We will + // use this to ensure any matches we find are in a language that this + // type system supports + const LanguageType language = GetLanguage(*die.GetCU()); + TypeSystemSP type_system = nullptr; + if (language != eLanguageTypeUnknown) { + auto type_system_or_err = GetTypeSystemForLanguage(language); + if (auto err = type_system_or_err.takeError()) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err), + "Cannot get TypeSystem for language {1}: {0}", + Language::GetNameForLanguageType(language)); } else { - // One name was NULL while the other wasn't - return false; + type_system = *type_system_or_err; } } - // We made it through all of the checks and the declaration contexts are - // equal. - return true; -} - -TypeSP -SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) { - TypeSP type_sp; - - if (die.GetName()) { - const dw_tag_t tag = die.Tag(); - - Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); - if (log) { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag={0}, " - "name='{1}')", - DW_TAG_value_to_name(tag), die.GetName()); - } - // Get the type system that we are looking to find a type for. We will - // use this to ensure any matches we find are in a language that this - // type system supports - const LanguageType language = GetLanguage(*die.GetCU()); - TypeSystemSP type_system = nullptr; - if (language != eLanguageTypeUnknown) { - auto type_system_or_err = GetTypeSystemForLanguage(language); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), std::move(err), - "Cannot get TypeSystem for language {1}: {0}", - Language::GetNameForLanguageType(language)); - } else { - type_system = *type_system_or_err; + // See comments below about -gsimple-template-names for why we attempt to + // compute missing template parameter names. + std::vector<std::string> template_params; + DWARFDeclContext die_dwarf_decl_ctx; + DWARFASTParser *dwarf_ast = + type_system ? type_system->GetDWARFParser() : nullptr; + for (DWARFDIE ctx_die = die; ctx_die && !isUnitType(ctx_die.Tag()); + ctx_die = ctx_die.GetParentDeclContextDIE()) { + die_dwarf_decl_ctx.AppendDeclContext(ctx_die.Tag(), ctx_die.GetName()); + template_params.push_back( + (ctx_die.IsStructUnionOrClass() && dwarf_ast) + ? dwarf_ast->GetDIEClassTemplateParams(ctx_die) + : ""); + } + const bool any_template_params = llvm::any_of( + template_params, [](llvm::StringRef p) { return !p.empty(); }); + + auto die_matches = [&](DWARFDIE type_die) { + // Resolve the type if both have the same tag or {class, struct} tags. + const bool tag_matches = + type_die.Tag() == tag || + (IsStructOrClassTag(type_die.Tag()) && IsStructOrClassTag(tag)); + if (!tag_matches) + return false; + if (any_template_params) { + size_t pos = 0; + for (DWARFDIE ctx_die = type_die; ctx_die && !isUnitType(ctx_die.Tag()) && + pos < template_params.size(); + ctx_die = ctx_die.GetParentDeclContextDIE(), ++pos) { + if (template_params[pos].empty()) + continue; + if (template_params[pos] != + dwarf_ast->GetDIEClassTemplateParams(ctx_die)) + return false; } + if (pos != template_params.size()) + return false; } + return true; + }; + DWARFDIE result; + m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) { + // Make sure type_die's language matches the type system we are + // looking for. We don't want to find a "Foo" type from Java if we + // are looking for a "Foo" type for C, C++, ObjC, or ObjC++. + if (type_system && + !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU()))) + return true; - // See comments below about -gsimple-template-names for why we attempt to - // compute missing template parameter names. - ConstString template_params; - if (type_system) { - DWARFASTParser *dwarf_ast = type_system->GetDWARFParser(); - if (dwarf_ast) - template_params = dwarf_ast->GetDIEClassTemplateParams(die); - } - - const DWARFDeclContext die_dwarf_decl_ctx = GetDWARFDeclContext(die); - m_index->GetFullyQualifiedType(die_dwarf_decl_ctx, [&](DWARFDIE type_die) { - // Make sure type_die's language matches the type system we are - // looking for. We don't want to find a "Foo" type from Java if we - // are looking for a "Foo" type for C, C++, ObjC, or ObjC++. - if (type_system && - !type_system->SupportsLanguage(GetLanguage(*type_die.GetCU()))) - return true; - - const dw_tag_t type_tag = type_die.Tag(); - // Resolve the type if both have the same tag or {class, struct} tags. - const bool try_resolving_type = - type_tag == tag || - (IsStructOrClassTag(type_tag) && IsStructOrClassTag(tag)); - - if (!try_resolving_type) { - if (log) { - GetObjectFile()->GetModule()->LogMessage( - log, - "SymbolFileDWARF::" - "FindDefinitionTypeForDWARFDeclContext(tag={0}, " - "name='{1}') ignoring die={2:x16} ({3})", - DW_TAG_value_to_name(tag), die.GetName(), type_die.GetOffset(), - type_die.GetName()); - } - return true; - } - + if (!die_matches(type_die)) { if (log) { - DWARFDeclContext type_dwarf_decl_ctx = GetDWARFDeclContext(type_die); GetObjectFile()->GetModule()->LogMessage( log, - "SymbolFileDWARF::" - "FindDefinitionTypeForDWARFDeclContext(tag={0}, " - "name='{1}') trying die={2:x16} ({3})", - DW_TAG_value_to_name(tag), die.GetName(), type_die.GetOffset(), - type_dwarf_decl_ctx.GetQualifiedName()); + "SymbolFileDWARF::FindDefinitionDIE(tag={0} ({1}), " + "name='{2}') ignoring die={3:x16} ({4})", + DW_TAG_value_to_name(tag), tag, name, type_die.GetOffset(), + type_die.GetName()); } + return true; + } - Type *resolved_type = ResolveType(type_die, false); - if (!resolved_type || resolved_type == DIE_IS_BEING_PARSED) - return true; - - // With -gsimple-template-names, the DIE name may not contain the template - // parameters. If the declaration has template parameters but doesn't - // contain '<', check that the child template parameters match. - if (template_params) { - llvm::StringRef test_base_name = - GetTypeForDIE(type_die)->GetBaseName().GetStringRef(); - auto i = test_base_name.find('<'); - - // Full name from clang AST doesn't contain '<' so this type_die isn't - // a template parameter, but we're expecting template parameters, so - // bail. - if (i == llvm::StringRef::npos) - return true; - - llvm::StringRef test_template_params = - test_base_name.slice(i, test_base_name.size()); - // Bail if template parameters don't match. - if (test_template_params != template_params.GetStringRef()) - return true; - } + if (log) { + DWARFDeclContext type_dwarf_decl_ctx = type_die.GetDWARFDeclContext(); + GetObjectFile()->GetModule()->LogMessage( + log, + "SymbolFileDWARF::FindDefinitionTypeDIE(tag={0} ({1}), name='{2}') " + "trying die={3:x16} ({4})", + DW_TAG_value_to_name(tag), tag, name, type_die.GetOffset(), + type_dwarf_decl_ctx.GetQualifiedName()); + } - type_sp = resolved_type->shared_from_this(); - return false; - }); - } - return type_sp; + result = type_die; + return false; + }); + return result; } TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die, @@ -3392,8 +3371,8 @@ static DWARFExpressionList GetExprListFromAtLocation(DWARFFormValue form_value, if (DWARFFormValue::IsBlockForm(form_value.Form())) { const DWARFDataExtractor &data = die.GetData(); - uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); + uint64_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint64_t block_length = form_value.Unsigned(); return DWARFExpressionList( module, DataExtractor(data, block_offset, block_length), die.GetCU()); } @@ -3422,9 +3401,9 @@ GetExprListFromAtConstValue(DWARFFormValue form_value, ModuleSP module, const DWARFDataExtractor &debug_info_data = die.GetData(); if (DWARFFormValue::IsBlockForm(form_value.Form())) { // Retrieve the value as a block expression. - uint32_t block_offset = + uint64_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); + uint64_t block_length = form_value.Unsigned(); return DWARFExpressionList( module, DataExtractor(debug_info_data, block_offset, block_length), die.GetCU()); @@ -3591,8 +3570,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if ((parent_tag == DW_TAG_compile_unit || parent_tag == DW_TAG_partial_unit) && Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) - mangled = - GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString(); + mangled = die.GetDWARFDeclContext() + .GetQualifiedNameAsConstString() + .GetCString(); } if (tag == DW_TAG_formal_parameter) @@ -3622,8 +3602,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, StreamString strm; location->DumpLocation(&strm, eDescriptionLevelFull, nullptr); GetObjectFile()->GetModule()->ReportError( - "{0:x16}: {1} has an invalid location: {2}", die.GetOffset(), - die.GetTagAsCString(), strm.GetData()); + "{0:x16}: {1} ({2}) has an invalid location: {3}", die.GetOffset(), + DW_TAG_value_to_name(die.Tag()), die.Tag(), strm.GetData()); } if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) is_static_lifetime = true; @@ -3743,7 +3723,7 @@ SymbolFileDWARF::FindBlockContainingSpecification( // Give the concrete function die specified by "func_die_offset", find the // concrete block whose DW_AT_specification or DW_AT_abstract_origin points // to "spec_block_die_offset" - return FindBlockContainingSpecification(DebugInfo().GetDIE(func_die_ref), + return FindBlockContainingSpecification(GetDIE(func_die_ref), spec_block_die_offset); } @@ -3811,10 +3791,11 @@ void SymbolFileDWARF::ParseAndAppendGlobalVariable( variable_list_sp = sc.comp_unit->GetVariableList(false); } else { GetObjectFile()->GetModule()->ReportError( - "parent {0:x8} {1} with no valid compile unit in " - "symbol context for {2:x8} {3}.\n", - sc_parent_die.GetID(), sc_parent_die.GetTagAsCString(), die.GetID(), - die.GetTagAsCString()); + "parent {0:x8} {1} ({2}) with no valid compile unit in " + "symbol context for {3:x8} {4} ({5}).\n", + sc_parent_die.GetID(), DW_TAG_value_to_name(sc_parent_die.Tag()), + sc_parent_die.Tag(), die.GetID(), DW_TAG_value_to_name(die.Tag()), + die.Tag()); return; } break; @@ -3822,8 +3803,8 @@ void SymbolFileDWARF::ParseAndAppendGlobalVariable( default: GetObjectFile()->GetModule()->ReportError( "didn't find appropriate parent DIE for variable list for {0:x8} " - "{1}.\n", - die.GetID(), die.GetTagAsCString()); + "{1} ({2}).\n", + die.GetID(), DW_TAG_value_to_name(die.Tag()), die.Tag()); return; } @@ -4033,8 +4014,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { if (!DWARFFormValue::IsBlockForm(form_value.Form())) return {}; auto data = child.GetData(); - uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); + uint64_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint64_t block_length = form_value.Unsigned(); return DWARFExpressionList( module, DataExtractor(data, block_offset, block_length), child.GetCU()); @@ -4139,8 +4120,8 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { } auto data = child.GetData(); - uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); + uint64_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint64_t block_length = form_value.Unsigned(); call_target = DWARFExpressionList( module, DataExtractor(data, block_offset, block_length), child.GetCU()); @@ -4322,26 +4303,59 @@ SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() { llvm::call_once(m_dwp_symfile_once_flag, [this]() { + // Create a list of files to try and append .dwp to. + FileSpecList symfiles; + // Append the module's object file path. + const FileSpec module_fspec = m_objfile_sp->GetModule()->GetFileSpec(); + symfiles.Append(module_fspec); + // Append the object file for this SymbolFile only if it is different from + // the module's file path. Our main module could be "a.out", our symbol file + // could be "a.debug" and our ".dwp" file might be "a.debug.dwp" instead of + // "a.out.dwp". + const FileSpec symfile_fspec(m_objfile_sp->GetFileSpec()); + if (symfile_fspec != module_fspec) { + symfiles.Append(symfile_fspec); + } else { + // If we don't have a separate debug info file, then try stripping the + // extension. The main module could be "a.debug" and the .dwp file could + // be "a.dwp" instead of "a.debug.dwp". + ConstString filename_no_ext = + module_fspec.GetFileNameStrippingExtension(); + if (filename_no_ext != module_fspec.GetFilename()) { + FileSpec module_spec_no_ext(module_fspec); + module_spec_no_ext.SetFilename(filename_no_ext); + symfiles.Append(module_spec_no_ext); + } + } + Log *log = GetLog(DWARFLog::SplitDwarf); + FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); ModuleSpec module_spec; module_spec.GetFileSpec() = m_objfile_sp->GetFileSpec(); - module_spec.GetSymbolFileSpec() = - FileSpec(m_objfile_sp->GetModule()->GetFileSpec().GetPath() + ".dwp"); - - module_spec.GetUUID() = m_objfile_sp->GetUUID(); - FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); - FileSpec dwp_filespec = - PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); - if (FileSystem::Instance().Exists(dwp_filespec)) { - DataBufferSP dwp_file_data_sp; - lldb::offset_t dwp_file_data_offset = 0; - ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin( - GetObjectFile()->GetModule(), &dwp_filespec, 0, - FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp, - dwp_file_data_offset); - if (!dwp_obj_file) - return; - m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>( - *this, dwp_obj_file, DIERef::k_file_index_mask); + for (const auto &symfile : symfiles.files()) { + module_spec.GetSymbolFileSpec() = + FileSpec(symfile.GetPath() + ".dwp", symfile.GetPathStyle()); + LLDB_LOG(log, "Searching for DWP using: \"{0}\"", + module_spec.GetSymbolFileSpec()); + FileSpec dwp_filespec = + PluginManager::LocateExecutableSymbolFile(module_spec, search_paths); + if (FileSystem::Instance().Exists(dwp_filespec)) { + LLDB_LOG(log, "Found DWP file: \"{0}\"", dwp_filespec); + DataBufferSP dwp_file_data_sp; + lldb::offset_t dwp_file_data_offset = 0; + ObjectFileSP dwp_obj_file = ObjectFile::FindPlugin( + GetObjectFile()->GetModule(), &dwp_filespec, 0, + FileSystem::Instance().GetByteSize(dwp_filespec), dwp_file_data_sp, + dwp_file_data_offset); + if (dwp_obj_file) { + m_dwp_symfile = std::make_shared<SymbolFileDWARFDwo>( + *this, dwp_obj_file, DIERef::k_file_index_mask); + break; + } + } + } + if (!m_dwp_symfile) { + LLDB_LOG(log, "Unable to locate for DWP file for: \"{0}\"", + m_objfile_sp->GetModule()->GetFileSpec()); } }); return m_dwp_symfile; @@ -4383,14 +4397,6 @@ SymbolFileDWARF::GetContainingDeclContext(const DWARFDIE &die) { return CompilerDeclContext(); } -DWARFDeclContext SymbolFileDWARF::GetDWARFDeclContext(const DWARFDIE &die) { - if (!die.IsValid()) - return {}; - DWARFDeclContext dwarf_decl_ctx = - die.GetDIE()->GetDWARFDeclContext(die.GetCU()); - return dwarf_decl_ctx; -} - LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) { // Note: user languages between lo_user and hi_user must be handled // explicitly here. diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 26a9502f90aa..4967b37d753a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -186,6 +186,8 @@ public: GetMangledNamesForFunction(const std::string &scope_qualified_name, std::vector<ConstString> &mangled_names) override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; + void FindTypes(const lldb_private::TypeQuery &match, lldb_private::TypeResults &results) override; @@ -239,6 +241,15 @@ public: return m_external_type_modules; } + /// Given a DIERef, find the correct SymbolFileDWARF. + /// + /// A DIERef contains a file index that can uniquely identify a N_OSO file for + /// DWARF in .o files on mac, or a .dwo or .dwp file index for split DWARF. + /// Calling this function will find the correct symbol file to use so that + /// further lookups can be done on the correct symbol file so that the DIE + /// offset makes sense in the DIERef. + virtual SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref); + virtual DWARFDIE GetDIE(const DIERef &die_ref); DWARFDIE GetDIE(lldb::user_id_t uid); @@ -250,6 +261,17 @@ public: /// If this is a DWARF object with a single CU, return its DW_AT_dwo_id. std::optional<uint64_t> GetDWOId(); + /// Given a DWO DWARFUnit, find the corresponding skeleton DWARFUnit + /// in the main symbol file. DWP files can have their DWARFUnits + /// parsed without the skeleton compile units having been parsed, so + /// sometimes we need to find the skeleton compile unit for a DWO + /// DWARFUnit so we can fill in this link. Currently unless the + /// skeleton compile unit has been parsed _and_ the Unit DIE has been + /// parsed, the DWO unit will not have a backward link setup correctly + /// which was causing crashes due to an assertion that was firing + /// in SymbolFileDWARF::GetCompUnitForDWARFCompUnit(). + DWARFUnit *GetSkeletonUnit(DWARFUnit *dwo_unit); + static bool DIEInDeclContext(const CompilerDeclContext &parent_decl_ctx, const DWARFDIE &die, bool only_root_namespaces = false); @@ -283,8 +305,6 @@ public: static CompilerDeclContext GetContainingDeclContext(const DWARFDIE &die); - static DWARFDeclContext GetDWARFDeclContext(const DWARFDIE &die); - static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); static lldb::LanguageType GetLanguage(DWARFUnit &unit); @@ -322,20 +342,8 @@ public: virtual DIEToTypePtr &GetDIEToType() { return m_die_to_type; } - typedef llvm::DenseMap<const DWARFDebugInfoEntry *, - lldb::opaque_compiler_type_t> - DIEToCompilerType; - - virtual DIEToCompilerType &GetForwardDeclDIEToCompilerType() { - return m_forward_decl_die_to_compiler_type; - } - - typedef llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> - CompilerTypeToDIE; - - virtual CompilerTypeToDIE &GetForwardDeclCompilerTypeToDIE() { - return m_forward_decl_compiler_type_to_die; - } + virtual llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> & + GetForwardDeclCompilerTypeToDIE(); typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> DIEToVariableSP; @@ -348,8 +356,7 @@ public: SymbolFileDWARFDebugMap *GetDebugMapSymfile(); - virtual lldb::TypeSP - FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die); + virtual DWARFDIE FindDefinitionDIE(const DWARFDIE &die); virtual lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( const DWARFDIE &die, ConstString type_name, bool must_be_implementation); @@ -360,6 +367,9 @@ public: Type *ResolveTypeUID(const DIERef &die_ref); + /// Returns the DWARFIndex for this symbol, if it exists. + DWARFIndex *getIndex() { return m_index.get(); } + protected: SymbolFileDWARF(const SymbolFileDWARF &) = delete; const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete; @@ -453,8 +463,6 @@ protected: FindBlockContainingSpecification(const DWARFDIE &die, dw_offset_t spec_block_die_offset); - bool DIEDeclContextsMatch(const DWARFDIE &die1, const DWARFDIE &die2); - bool ClassContainsSelector(const DWARFDIE &class_die, ConstString selector); /// Parse call site entries (DW_TAG_call_site), including any nested call site @@ -525,10 +533,14 @@ protected: NameToOffsetMap m_function_scope_qualified_name_map; std::unique_ptr<DWARFDebugRanges> m_ranges; UniqueDWARFASTTypeMap m_unique_ast_type_map; + // A map from DIE to lldb_private::Type. For record type, the key might be + // either declaration DIE or definition DIE. DIEToTypePtr m_die_to_type; DIEToVariableSP m_die_to_variable_sp; - DIEToCompilerType m_forward_decl_die_to_compiler_type; - CompilerTypeToDIE m_forward_decl_compiler_type_to_die; + // A map from CompilerType to the struct/class/union/enum DIE (might be a + // declaration or a definition) that is used to construct it. + llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> + m_forward_decl_compiler_type_to_die; llvm::DenseMap<dw_offset_t, std::unique_ptr<SupportFileList>> m_type_unit_support_files; std::vector<uint32_t> m_lldb_cu_to_dwarf_unit; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 6dd3eb3677b7..64cde16433ef 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -37,6 +37,7 @@ #include "LogChannelDWARF.h" #include "SymbolFileDWARF.h" +#include "lldb/lldb-private-enumerations.h" #include <memory> #include <optional> @@ -803,13 +804,13 @@ SymbolFileDWARFDebugMap::GetDynamicArrayInfoForUID( bool SymbolFileDWARFDebugMap::CompleteType(CompilerType &compiler_type) { bool success = false; if (compiler_type) { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { if (oso_dwarf->HasForwardDeclForCompilerType(compiler_type)) { oso_dwarf->CompleteType(compiler_type); success = true; - return true; + return IterationAction::Stop; } - return false; + return IterationAction::Continue; }); } return success; @@ -847,9 +848,17 @@ SymbolFileDWARFDebugMap::ResolveSymbolContext(const Address &exe_so_addr, debug_map_entry->data.GetOSOFileAddress(); Address oso_so_addr; if (oso_module->ResolveFileAddress(oso_file_addr, oso_so_addr)) { - resolved_flags |= - oso_module->GetSymbolFile()->ResolveSymbolContext( - oso_so_addr, resolve_scope, sc); + if (SymbolFile *sym_file = oso_module->GetSymbolFile()) { + resolved_flags |= sym_file->ResolveSymbolContext( + oso_so_addr, resolve_scope, sc); + } else { + ObjectFile *obj_file = GetObjectFile(); + LLDB_LOG(GetLog(DWARFLog::DebugMap), + "Failed to get symfile for OSO: {0} in module: {1}", + oso_module->GetFileSpec(), + obj_file ? obj_file->GetFileSpec() + : FileSpec("unknown")); + } } } } @@ -915,7 +924,7 @@ void SymbolFileDWARFDebugMap::FindGlobalVariables( std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); uint32_t total_matches = 0; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { const uint32_t old_size = variables.GetSize(); oso_dwarf->FindGlobalVariables(name, parent_decl_ctx, max_matches, variables); @@ -925,18 +934,18 @@ void SymbolFileDWARFDebugMap::FindGlobalVariables( // Are we getting all matches? if (max_matches == UINT32_MAX) - return false; // Yep, continue getting everything + return IterationAction::Continue; // Yep, continue getting everything // If we have found enough matches, lets get out if (max_matches >= total_matches) - return true; + return IterationAction::Stop; // Update the max matches for any subsequent calls to find globals in any // other object files with DWARF max_matches -= oso_matches; } - return false; + return IterationAction::Continue; }); } @@ -945,7 +954,7 @@ void SymbolFileDWARFDebugMap::FindGlobalVariables( VariableList &variables) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); uint32_t total_matches = 0; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { const uint32_t old_size = variables.GetSize(); oso_dwarf->FindGlobalVariables(regex, max_matches, variables); @@ -955,18 +964,18 @@ void SymbolFileDWARFDebugMap::FindGlobalVariables( // Are we getting all matches? if (max_matches == UINT32_MAX) - return false; // Yep, continue getting everything + return IterationAction::Continue; // Yep, continue getting everything // If we have found enough matches, lets get out if (max_matches >= total_matches) - return true; + return IterationAction::Stop; // Update the max matches for any subsequent calls to find globals in any // other object files with DWARF max_matches -= oso_matches; } - return false; + return IterationAction::Continue; }); } @@ -1071,7 +1080,7 @@ void SymbolFileDWARFDebugMap::FindFunctions( LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (name = %s)", lookup_info.GetLookupName().GetCString()); - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { uint32_t sc_idx = sc_list.GetSize(); oso_dwarf->FindFunctions(lookup_info, parent_decl_ctx, include_inlines, sc_list); @@ -1079,7 +1088,7 @@ void SymbolFileDWARFDebugMap::FindFunctions( RemoveFunctionsWithModuleNotEqualTo(m_objfile_sp->GetModule(), sc_list, sc_idx); } - return false; + return IterationAction::Continue; }); } @@ -1090,7 +1099,7 @@ void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", regex.GetText().str().c_str()); - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { uint32_t sc_idx = sc_list.GetSize(); oso_dwarf->FindFunctions(regex, include_inlines, sc_list); @@ -1098,7 +1107,7 @@ void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, RemoveFunctionsWithModuleNotEqualTo(m_objfile_sp->GetModule(), sc_list, sc_idx); } - return false; + return IterationAction::Continue; }); } @@ -1121,9 +1130,9 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, oso_dwarf->GetTypes(sc_scope, type_mask, type_list); } } else { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { oso_dwarf->GetTypes(sc_scope, type_mask, type_list); - return false; + return IterationAction::Continue; }); } } @@ -1138,27 +1147,26 @@ SymbolFileDWARFDebugMap::ParseCallEdgesInFunction( return {}; } -TypeSP SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext( - const DWARFDIE &die) { - TypeSP type_sp; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { - type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext(die); - return ((bool)type_sp); +DWARFDIE SymbolFileDWARFDebugMap::FindDefinitionDIE(const DWARFDIE &die) { + DWARFDIE result; + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { + result = oso_dwarf->FindDefinitionDIE(die); + return result ? IterationAction::Stop : IterationAction::Continue; }); - return type_sp; + return result; } bool SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type( SymbolFileDWARF *skip_dwarf_oso) { if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { if (skip_dwarf_oso != oso_dwarf && oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(nullptr)) { m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes; - return true; + return IterationAction::Stop; } - return false; + return IterationAction::Continue; }); } return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes; @@ -1217,10 +1225,10 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( if (!must_be_implementation) { TypeSP type_sp; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE( die, type_name, must_be_implementation); - return (bool)type_sp; + return type_sp ? IterationAction::Stop : IterationAction::Continue; }); return type_sp; @@ -1231,9 +1239,10 @@ TypeSP SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE( void SymbolFileDWARFDebugMap::FindTypes(const TypeQuery &query, TypeResults &results) { std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { oso_dwarf->FindTypes(query, results); - return !results.Done(query); // Keep iterating if we aren't done. + return results.Done(query) ? IterationAction::Stop + : IterationAction::Continue; }); } @@ -1243,23 +1252,24 @@ CompilerDeclContext SymbolFileDWARFDebugMap::FindNamespace( std::lock_guard<std::recursive_mutex> guard(GetModuleMutex()); CompilerDeclContext matching_namespace; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { matching_namespace = oso_dwarf->FindNamespace(name, parent_decl_ctx, only_root_namespaces); - return (bool)matching_namespace; + return matching_namespace ? IterationAction::Stop + : IterationAction::Continue; }); return matching_namespace; } void SymbolFileDWARFDebugMap::DumpClangAST(Stream &s) { - ForEachSymbolFile([&s](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&s](SymbolFileDWARF *oso_dwarf) { oso_dwarf->DumpClangAST(s); // The underlying assumption is that DumpClangAST(...) will obtain the // AST from the underlying TypeSystem and therefore we only need to do // this once and can stop after the first iteration hence we return true. - return true; + return IterationAction::Stop; }); } @@ -1389,9 +1399,9 @@ SymbolFileDWARFDebugMap::GetCompilerContextForUID(lldb::user_id_t type_uid) { void SymbolFileDWARFDebugMap::ParseDeclsForContext( lldb_private::CompilerDeclContext decl_ctx) { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { oso_dwarf->ParseDeclsForContext(decl_ctx); - return true; // Keep iterating + return IterationAction::Continue; }); } @@ -1519,14 +1529,14 @@ SymbolFileDWARFDebugMap::AddOSOARanges(SymbolFileDWARF *dwarf2Data, ModuleList SymbolFileDWARFDebugMap::GetDebugInfoModules() { ModuleList oso_modules; - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { ObjectFile *oso_objfile = oso_dwarf->GetObjectFile(); if (oso_objfile) { ModuleSP module_sp = oso_objfile->GetModule(); if (module_sp) oso_modules.Append(module_sp); } - return false; // Keep iterating + return IterationAction::Continue; }); return oso_modules; } @@ -1579,8 +1589,8 @@ Status SymbolFileDWARFDebugMap::CalculateFrameVariableError(StackFrame &frame) { void SymbolFileDWARFDebugMap::GetCompileOptions( std::unordered_map<lldb::CompUnitSP, lldb_private::Args> &args) { - ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { + ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) { oso_dwarf->GetCompileOptions(args); - return false; + return IterationAction::Continue; }); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index d639ee500080..34cb52e5b601 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -20,6 +20,7 @@ #include "UniqueDWARFASTType.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-private-enumerations.h" class DWARFASTParserClang; @@ -233,13 +234,14 @@ protected: SymbolFileDWARF *GetSymbolFileByOSOIndex(uint32_t oso_idx); - // If closure returns "false", iteration continues. If it returns - // "true", iteration terminates. - void ForEachSymbolFile(std::function<bool(SymbolFileDWARF *)> closure) { + /// If closure returns \ref IterationAction::Continue, iteration + /// continues. Otherwise, iteration terminates. + void + ForEachSymbolFile(std::function<IterationAction(SymbolFileDWARF *)> closure) { for (uint32_t oso_idx = 0, num_oso_idxs = m_compile_unit_infos.size(); oso_idx < num_oso_idxs; ++oso_idx) { if (SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(oso_idx)) { - if (closure(oso_dwarf)) + if (closure(oso_dwarf) == IterationAction::Stop) return; } } @@ -275,13 +277,18 @@ protected: CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf); - lldb::TypeSP FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die); + DWARFDIE FindDefinitionDIE(const DWARFDIE &die); bool Supports_DW_AT_APPLE_objc_complete_type(SymbolFileDWARF *skip_dwarf_oso); lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE( const DWARFDIE &die, ConstString type_name, bool must_be_implementation); + llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> & + GetForwardDeclCompilerTypeToDIE() { + return m_forward_decl_compiler_type_to_die; + } + UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() { return m_unique_ast_type_map; } @@ -319,6 +326,10 @@ protected: std::vector<uint32_t> m_func_indexes; // Sorted by address std::vector<uint32_t> m_glob_indexes; std::map<std::pair<ConstString, llvm::sys::TimePoint<>>, OSOInfoSP> m_oso_map; + // A map from CompilerType to the struct/class/union/enum DIE (might be a + // declaration or a definition) that is used to construct it. + llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> + m_forward_decl_compiler_type_to_die; UniqueDWARFASTTypeMap m_unique_ast_type_map; LazyBool m_supports_DW_AT_APPLE_objc_complete_type; DebugMap m_debug_map; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index ca698a84a914..49632e1d8911 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -85,6 +85,17 @@ lldb::offset_t SymbolFileDWARFDwo::GetVendorDWARFOpcodeSize( return GetBaseSymbolFile().GetVendorDWARFOpcodeSize(data, data_offset, op); } +uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) { + // Directly get debug info from current dwo object file's section list + // instead of asking SymbolFileCommon::GetDebugInfo() which parses from + // owning module which is wrong. + SectionList *section_list = + m_objfile_sp->GetSectionList(/*update_module_section_list=*/false); + if (section_list) + return section_list->GetDebugInfoSize(); + return 0; +} + bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode( uint8_t op, const lldb_private::DataExtractor &opcodes, lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const { @@ -99,12 +110,7 @@ SymbolFileDWARF::DIEToVariableSP &SymbolFileDWARFDwo::GetDIEToVariable() { return GetBaseSymbolFile().GetDIEToVariable(); } -SymbolFileDWARF::DIEToCompilerType & -SymbolFileDWARFDwo::GetForwardDeclDIEToCompilerType() { - return GetBaseSymbolFile().GetForwardDeclDIEToCompilerType(); -} - -SymbolFileDWARF::CompilerTypeToDIE & +llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> & SymbolFileDWARFDwo::GetForwardDeclCompilerTypeToDIE() { return GetBaseSymbolFile().GetForwardDeclCompilerTypeToDIE(); } @@ -119,9 +125,8 @@ UniqueDWARFASTTypeMap &SymbolFileDWARFDwo::GetUniqueDWARFASTTypeMap() { return GetBaseSymbolFile().GetUniqueDWARFASTTypeMap(); } -lldb::TypeSP -SymbolFileDWARFDwo::FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) { - return GetBaseSymbolFile().FindDefinitionTypeForDWARFDeclContext(die); +DWARFDIE SymbolFileDWARFDwo::FindDefinitionDIE(const DWARFDIE &die) { + return GetBaseSymbolFile().FindDefinitionDIE(die); } lldb::TypeSP SymbolFileDWARFDwo::FindCompleteObjCDefinitionTypeForDIE( @@ -139,7 +144,7 @@ SymbolFileDWARFDwo::GetTypeSystemForLanguage(LanguageType language) { DWARFDIE SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) { if (die_ref.file_index() == GetFileIndex()) - return DebugInfo().GetDIE(die_ref); + return DebugInfo().GetDIE(die_ref.section(), die_ref.die_offset()); return GetBaseSymbolFile().GetDIE(die_ref); } @@ -149,3 +154,27 @@ void SymbolFileDWARFDwo::FindGlobalVariables( GetBaseSymbolFile().FindGlobalVariables(name, parent_decl_ctx, max_matches, variables); } + +bool SymbolFileDWARFDwo::GetDebugInfoIndexWasLoadedFromCache() const { + return GetBaseSymbolFile().GetDebugInfoIndexWasLoadedFromCache(); +} +void SymbolFileDWARFDwo::SetDebugInfoIndexWasLoadedFromCache() { + GetBaseSymbolFile().SetDebugInfoIndexWasLoadedFromCache(); +} +bool SymbolFileDWARFDwo::GetDebugInfoIndexWasSavedToCache() const { + return GetBaseSymbolFile().GetDebugInfoIndexWasSavedToCache(); +} +void SymbolFileDWARFDwo::SetDebugInfoIndexWasSavedToCache() { + GetBaseSymbolFile().SetDebugInfoIndexWasSavedToCache(); +} +bool SymbolFileDWARFDwo::GetDebugInfoHadFrameVariableErrors() const { + return GetBaseSymbolFile().GetDebugInfoHadFrameVariableErrors(); +} +void SymbolFileDWARFDwo::SetDebugInfoHadFrameVariableErrors() { + return GetBaseSymbolFile().SetDebugInfoHadFrameVariableErrors(); +} + +SymbolFileDWARF * +SymbolFileDWARFDwo::GetDIERefSymbolFile(const DIERef &die_ref) { + return GetBaseSymbolFile().GetDIERefSymbolFile(die_ref); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 9f5950e51b0c..15c28fefd81f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -47,6 +47,8 @@ public: const lldb::offset_t data_offset, const uint8_t op) const override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; + bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, lldb::offset_t &offset, std::vector<Value> &stack) const override; @@ -56,27 +58,34 @@ public: uint32_t max_matches, VariableList &variables) override; + SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; } + + bool GetDebugInfoIndexWasLoadedFromCache() const override; + void SetDebugInfoIndexWasLoadedFromCache() override; + bool GetDebugInfoIndexWasSavedToCache() const override; + void SetDebugInfoIndexWasSavedToCache() override; + bool GetDebugInfoHadFrameVariableErrors() const override; + void SetDebugInfoHadFrameVariableErrors() override; + + SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override; + protected: DIEToTypePtr &GetDIEToType() override; DIEToVariableSP &GetDIEToVariable() override; - DIEToCompilerType &GetForwardDeclDIEToCompilerType() override; - - CompilerTypeToDIE &GetForwardDeclCompilerTypeToDIE() override; + llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> & + GetForwardDeclCompilerTypeToDIE() override; UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override; - lldb::TypeSP - FindDefinitionTypeForDWARFDeclContext(const DWARFDIE &die) override; + DWARFDIE FindDefinitionDIE(const DWARFDIE &die) override; lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die, ConstString type_name, bool must_be_implementation) override; - SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; } - /// If this file contains exactly one compile unit, this function will return /// it. Otherwise it returns nullptr. DWARFCompileUnit *FindSingleCompileUnit(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 223518f0ae82..3d201e96f92c 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -13,66 +13,75 @@ using namespace lldb_private::dwarf; using namespace lldb_private::plugin::dwarf; -bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, - const lldb_private::Declaration &decl, - const int32_t byte_size, - UniqueDWARFASTType &entry) const { - for (const UniqueDWARFASTType &udt : m_collection) { - // Make sure the tags match - if (udt.m_die.Tag() == die.Tag()) { - // Validate byte sizes of both types only if both are valid. - if (udt.m_byte_size < 0 || byte_size < 0 || - udt.m_byte_size == byte_size) { - // Make sure the file and line match - if (udt.m_declaration == decl) { - // The type has the same name, and was defined on the same file and - // line. Now verify all of the parent DIEs match. - DWARFDIE parent_arg_die = die.GetParent(); - DWARFDIE parent_pos_die = udt.m_die.GetParent(); - bool match = true; - bool done = false; - while (!done && match && parent_arg_die && parent_pos_die) { - const dw_tag_t parent_arg_tag = parent_arg_die.Tag(); - const dw_tag_t parent_pos_tag = parent_pos_die.Tag(); - if (parent_arg_tag == parent_pos_tag) { - switch (parent_arg_tag) { - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - case DW_TAG_namespace: { - const char *parent_arg_die_name = parent_arg_die.GetName(); - if (parent_arg_die_name == - nullptr) // Anonymous (i.e. no-name) struct - { - match = false; - } else { - const char *parent_pos_die_name = parent_pos_die.GetName(); - if (parent_pos_die_name == nullptr || - ((parent_arg_die_name != parent_pos_die_name) && - strcmp(parent_arg_die_name, parent_pos_die_name))) - match = false; - } - } break; +static bool IsStructOrClassTag(llvm::dwarf::Tag Tag) { + return Tag == llvm::dwarf::Tag::DW_TAG_class_type || + Tag == llvm::dwarf::Tag::DW_TAG_structure_type; +} - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - done = true; - break; - default: - break; - } +UniqueDWARFASTType *UniqueDWARFASTTypeList::Find( + const DWARFDIE &die, const lldb_private::Declaration &decl, + const int32_t byte_size, bool is_forward_declaration) { + for (UniqueDWARFASTType &udt : m_collection) { + // Make sure the tags match + if (udt.m_die.Tag() == die.Tag() || (IsStructOrClassTag(udt.m_die.Tag()) && + IsStructOrClassTag(die.Tag()))) { + // If they are not both definition DIEs or both declaration DIEs, then + // don't check for byte size and declaration location, because declaration + // DIEs usually don't have those info. + bool matching_size_declaration = + udt.m_is_forward_declaration != is_forward_declaration + ? true + : (udt.m_byte_size < 0 || byte_size < 0 || + udt.m_byte_size == byte_size) && + udt.m_declaration == decl; + if (!matching_size_declaration) + continue; + // The type has the same name, and was defined on the same file and + // line. Now verify all of the parent DIEs match. + DWARFDIE parent_arg_die = die.GetParent(); + DWARFDIE parent_pos_die = udt.m_die.GetParent(); + bool match = true; + bool done = false; + while (!done && match && parent_arg_die && parent_pos_die) { + const dw_tag_t parent_arg_tag = parent_arg_die.Tag(); + const dw_tag_t parent_pos_tag = parent_pos_die.Tag(); + if (parent_arg_tag == parent_pos_tag || + (IsStructOrClassTag(parent_arg_tag) && + IsStructOrClassTag(parent_pos_tag))) { + switch (parent_arg_tag) { + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_namespace: { + const char *parent_arg_die_name = parent_arg_die.GetName(); + if (parent_arg_die_name == nullptr) { + // Anonymous (i.e. no-name) struct + match = false; + } else { + const char *parent_pos_die_name = parent_pos_die.GetName(); + if (parent_pos_die_name == nullptr || + ((parent_arg_die_name != parent_pos_die_name) && + strcmp(parent_arg_die_name, parent_pos_die_name))) + match = false; } - parent_arg_die = parent_arg_die.GetParent(); - parent_pos_die = parent_pos_die.GetParent(); - } + } break; - if (match) { - entry = udt; - return true; + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + done = true; + break; + default: + break; } } + parent_arg_die = parent_arg_die.GetParent(); + parent_pos_die = parent_pos_die.GetParent(); + } + + if (match) { + return &udt; } } } - return false; + return nullptr; } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h index bf3cbae55e5c..9215484fa2ea 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -15,6 +15,7 @@ #include "DWARFDIE.h" #include "lldb/Core/Declaration.h" +#include "lldb/Symbol/Type.h" namespace lldb_private::plugin { namespace dwarf { @@ -23,31 +24,34 @@ public: // Constructors and Destructors UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {} - UniqueDWARFASTType(lldb::TypeSP &type_sp, const DWARFDIE &die, - const Declaration &decl, int32_t byte_size) - : m_type_sp(type_sp), m_die(die), m_declaration(decl), - m_byte_size(byte_size) {} - UniqueDWARFASTType(const UniqueDWARFASTType &rhs) : m_type_sp(rhs.m_type_sp), m_die(rhs.m_die), - m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size) {} + m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size), + m_is_forward_declaration(rhs.m_is_forward_declaration) {} ~UniqueDWARFASTType() = default; - UniqueDWARFASTType &operator=(const UniqueDWARFASTType &rhs) { - if (this != &rhs) { - m_type_sp = rhs.m_type_sp; - m_die = rhs.m_die; - m_declaration = rhs.m_declaration; - m_byte_size = rhs.m_byte_size; - } - return *this; + // This UniqueDWARFASTType might be created from declaration, update its info + // to definition DIE. + void UpdateToDefDIE(const DWARFDIE &def_die, Declaration &declaration, + int32_t byte_size) { + // Need to update Type ID to refer to the definition DIE, because + // it's used in DWARFASTParserClang::ParseCXXMethod to determine if we need + // to copy cxx method types from a declaration DIE to this definition DIE. + m_type_sp->SetID(def_die.GetID()); + if (declaration.IsValid()) + m_declaration = declaration; + if (byte_size) + m_byte_size = byte_size; + m_is_forward_declaration = false; } lldb::TypeSP m_type_sp; DWARFDIE m_die; Declaration m_declaration; int32_t m_byte_size = -1; + // True if the m_die is a forward declaration DIE. + bool m_is_forward_declaration = true; }; class UniqueDWARFASTTypeList { @@ -62,8 +66,9 @@ public: m_collection.push_back(entry); } - bool Find(const DWARFDIE &die, const Declaration &decl, - const int32_t byte_size, UniqueDWARFASTType &entry) const; + UniqueDWARFASTType *Find(const DWARFDIE &die, const Declaration &decl, + const int32_t byte_size, + bool is_forward_declaration); protected: typedef std::vector<UniqueDWARFASTType> collection; @@ -80,14 +85,15 @@ public: m_collection[name.GetCString()].Append(entry); } - bool Find(ConstString name, const DWARFDIE &die, const Declaration &decl, - const int32_t byte_size, UniqueDWARFASTType &entry) const { + UniqueDWARFASTType *Find(ConstString name, const DWARFDIE &die, + const Declaration &decl, const int32_t byte_size, + bool is_forward_declaration) { const char *unique_name_cstr = name.GetCString(); - collection::const_iterator pos = m_collection.find(unique_name_cstr); + collection::iterator pos = m_collection.find(unique_name_cstr); if (pos != m_collection.end()) { - return pos->second.Find(die, decl, byte_size, entry); + return pos->second.Find(die, decl, byte_size, is_forward_declaration); } - return false; + return nullptr; } protected: diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 745685a1b31d..7fded6a31a3a 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -2156,7 +2156,7 @@ SymbolFileNativePDB::GetTypeSystemForLanguage(lldb::LanguageType language) { return type_system_or_err; } -uint64_t SymbolFileNativePDB::GetDebugInfoSize() { +uint64_t SymbolFileNativePDB::GetDebugInfoSize(bool load_all_debug_info) { // PDB files are a separate file that contains all debug info. return m_index->pdb().getFileSize(); } diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index 82577771f355..669c44aa131e 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -77,7 +77,7 @@ public: void InitializeObject() override; - uint64_t GetDebugInfoSize() override; + uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override; // Compile Unit function calls diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index fab3ca989c0e..17c5f6118603 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -47,15 +47,18 @@ UdtRecordCompleter::UdtRecordCompleter( CVType cvt = m_index.tpi().getType(m_id.index); switch (cvt.kind()) { case LF_ENUM: + m_cvr.er.Options = ClassOptions::None; llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, m_cvr.er)); break; case LF_UNION: + m_cvr.ur.Options = ClassOptions::None; llvm::cantFail(TypeDeserializer::deserializeAs<UnionRecord>(cvt, m_cvr.ur)); m_layout.bit_size = m_cvr.ur.getSize() * 8; m_record.record.kind = Member::Union; break; case LF_CLASS: case LF_STRUCTURE: + m_cvr.cr.Options = ClassOptions::None; llvm::cantFail(TypeDeserializer::deserializeAs<ClassRecord>(cvt, m_cvr.cr)); m_layout.bit_size = m_cvr.cr.getSize() * 8; m_record.record.kind = Member::Struct; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index e915bff9e4a4..d656ca3facf7 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -1139,7 +1139,7 @@ PDBASTParser::FindNamespaceDecl(const clang::DeclContext *parent, assert(set); for (clang::NamespaceDecl *namespace_decl : *set) - if (namespace_decl->getName().equals(name)) + if (namespace_decl->getName() == name) return namespace_decl; for (clang::NamespaceDecl *namespace_decl : *set) diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index b26beecc6d12..9a282acae91f 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -1141,8 +1141,8 @@ void SymbolFilePDB::FindGlobalVariables( sc.module_sp = m_objfile_sp->GetModule(); lldbassert(sc.module_sp.get()); - if (!name.GetStringRef().equals( - MSVCUndecoratedNameParser::DropScope(pdb_data->getName()))) + if (name.GetStringRef() != + MSVCUndecoratedNameParser::DropScope(pdb_data->getName())) continue; sc.comp_unit = ParseCompileUnitForUID(GetCompilandId(*pdb_data)).get(); diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp index 9f32d252b22f..69595c6c14e4 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp @@ -776,6 +776,10 @@ std::optional<FileSpec> SymbolLocatorDebugSymbols::LocateExecutableSymbolFile( exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); + Progress progress( + "Locating external symbol file", + module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")); + FileSpec symbol_fspec; ModuleSpec dsym_module_spec; // First try and find the dSYM in the same directory as the executable or in @@ -1045,33 +1049,38 @@ bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile( if (!dsymForUUID_exe_spec) return false; + // Create the dsymForUUID command. const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath(); const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : ""; - const std::string file_path_str = - file_spec_ptr ? file_spec_ptr->GetPath() : ""; - Log *log = GetLog(LLDBLog::Host); + std::string lookup_arg = uuid_str; + if (lookup_arg.empty()) + lookup_arg = file_spec_ptr ? file_spec_ptr->GetPath() : ""; + if (lookup_arg.empty()) + return false; - // Create the dsymForUUID command. StreamString command; - const char *copy_executable_arg = copy_executable ? "--copyExecutable " : ""; - if (!uuid_str.empty()) { - command.Printf("%s --ignoreNegativeCache %s%s", - dsymForUUID_exe_path.c_str(), copy_executable_arg, - uuid_str.c_str()); - LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s", - dsymForUUID_exe_path.c_str(), uuid_str.c_str(), - command.GetString().data()); - } else if (!file_path_str.empty()) { - command.Printf("%s --ignoreNegativeCache %s%s", - dsymForUUID_exe_path.c_str(), copy_executable_arg, - file_path_str.c_str()); - LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s", - dsymForUUID_exe_path.c_str(), file_path_str.c_str(), - command.GetString().data()); - } else { - return false; - } + command << dsymForUUID_exe_path << " --ignoreNegativeCache "; + if (copy_executable) + command << "--copyExecutable "; + command << lookup_arg; + + // Log and report progress. + std::string lookup_desc; + if (uuid_ptr && file_spec_ptr) + lookup_desc = + llvm::formatv("{0} ({1})", file_spec_ptr->GetFilename().GetString(), + uuid_ptr->GetAsString()); + else if (uuid_ptr) + lookup_desc = uuid_ptr->GetAsString(); + else if (file_spec_ptr) + lookup_desc = file_spec_ptr->GetFilename().GetString(); + + Log *log = GetLog(LLDBLog::Host); + LLDB_LOG(log, "Calling {0} for {1} to find dSYM: {2}", dsymForUUID_exe_path, + lookup_desc, command.GetString()); + + Progress progress("Downloading symbol file for", lookup_desc); // Invoke dsymForUUID. int exit_status = -1; diff --git a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp index 6f0126b16cdc..919f26ba7012 100644 --- a/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp @@ -36,6 +36,10 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/ThreadPool.h" +#if defined(__FreeBSD__) +#include <sys/sysctl.h> +#endif + // From MacOSX system header "mach/machine.h" typedef int cpu_type_t; typedef int cpu_subtype_t; @@ -141,6 +145,24 @@ std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile( FileSystem::Instance().Resolve(file_spec); debug_file_search_paths.AppendIfUnique(file_spec); } +#if defined(__FreeBSD__) + // Add $LOCALBASE/lib/debug directory, where LOCALBASE is + // usually /usr/local, but may be adjusted by the end user. + { + int mib[2]; + char buf[PATH_MAX]; + size_t len = PATH_MAX; + + mib[0] = CTL_USER; + mib[1] = USER_LOCALBASE; + if (::sysctl(mib, 2, buf, &len, NULL, 0) == 0) { + FileSpec file_spec("/lib/debug"); + file_spec.PrependPathComponent(llvm::StringRef(buf)); + FileSystem::Instance().Resolve(file_spec); + debug_file_search_paths.AppendIfUnique(file_spec); + } + } +#endif // __FreeBSD__ #endif #endif // _WIN32 } diff --git a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index d6a21ad560c4..0fda681188d9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1,4 +1,4 @@ -//===-- TypeSystemClang.cpp -----------------------------------------------==='// +//===-- TypeSystemClang.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +9,7 @@ #include "TypeSystemClang.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/ExprCXX.h" #include "llvm/Support/Casting.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -459,84 +460,19 @@ TypeSystemClang::ConvertAccessTypeToAccessSpecifier(AccessType access) { return AS_none; } -static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { +static void ParseLangArgs(LangOptions &Opts, ArchSpec arch) { // FIXME: Cleanup per-file based stuff. - // Set some properties which depend solely on the input kind; it would be - // nice to move these to the language standard, and have the driver resolve - // the input kind + language standard. - if (IK.getLanguage() == clang::Language::Asm) { - Opts.AsmPreprocessor = 1; - } else if (IK.isObjectiveC()) { - Opts.ObjC = 1; - } - - LangStandard::Kind LangStd = LangStandard::lang_unspecified; - - if (LangStd == LangStandard::lang_unspecified) { - // Based on the base language, pick one. - switch (IK.getLanguage()) { - case clang::Language::Unknown: - case clang::Language::LLVM_IR: - case clang::Language::RenderScript: - llvm_unreachable("Invalid input kind!"); - case clang::Language::OpenCL: - LangStd = LangStandard::lang_opencl10; - break; - case clang::Language::OpenCLCXX: - LangStd = LangStandard::lang_openclcpp10; - break; - case clang::Language::Asm: - case clang::Language::C: - case clang::Language::ObjC: - LangStd = LangStandard::lang_gnu99; - break; - case clang::Language::CXX: - case clang::Language::ObjCXX: - LangStd = LangStandard::lang_gnucxx98; - break; - case clang::Language::CUDA: - case clang::Language::HIP: - LangStd = LangStandard::lang_gnucxx17; - break; - case clang::Language::HLSL: - LangStd = LangStandard::lang_hlsl; - break; - } - } - - const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Opts.LineComment = Std.hasLineComments(); - Opts.C99 = Std.isC99(); - Opts.CPlusPlus = Std.isCPlusPlus(); - Opts.CPlusPlus11 = Std.isCPlusPlus11(); - Opts.CPlusPlus14 = Std.isCPlusPlus14(); - Opts.CPlusPlus17 = Std.isCPlusPlus17(); - Opts.CPlusPlus20 = Std.isCPlusPlus20(); - Opts.Digraphs = Std.hasDigraphs(); - Opts.GNUMode = Std.isGNUMode(); - Opts.GNUInline = !Std.isC99(); - Opts.HexFloats = Std.hasHexFloats(); - - Opts.WChar = true; - - // OpenCL has some additional defaults. - if (LangStd == LangStandard::lang_opencl10) { - Opts.OpenCL = 1; - Opts.AltiVec = 1; - Opts.CXXOperatorNames = 1; - Opts.setLaxVectorConversions(LangOptions::LaxVectorConversionKind::All); - } - - // OpenCL and C++ both have bool, true, false keywords. - Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + std::vector<std::string> Includes; + LangOptions::setLangDefaults(Opts, clang::Language::ObjCXX, arch.GetTriple(), + Includes, clang::LangStandard::lang_gnucxx98); Opts.setValueVisibilityMode(DefaultVisibility); // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs is // specified, or -std is set to a conforming mode. Opts.Trigraphs = !Opts.GNUMode; - Opts.CharIsSigned = ArchSpec(triple).CharIsSignedByDefault(); + Opts.CharIsSigned = arch.CharIsSignedByDefault(); Opts.OptimizeSize = 0; // FIXME: Eliminate this dependency. @@ -565,6 +501,8 @@ TypeSystemClang::TypeSystemClang(llvm::StringRef name, // The caller didn't pass an ASTContext so create a new one for this // TypeSystemClang. CreateASTContext(); + + LogCreation(); } TypeSystemClang::TypeSystemClang(llvm::StringRef name, @@ -574,6 +512,8 @@ TypeSystemClang::TypeSystemClang(llvm::StringRef name, m_ast_up.reset(&existing_ctxt); GetASTMap().Insert(&existing_ctxt, this); + + LogCreation(); } // Destructor @@ -694,7 +634,7 @@ void TypeSystemClang::SetExternalSource( ast.setExternalSource(ast_source_up); } -ASTContext &TypeSystemClang::getASTContext() { +ASTContext &TypeSystemClang::getASTContext() const { assert(m_ast_up); return *m_ast_up; } @@ -726,8 +666,7 @@ void TypeSystemClang::CreateASTContext() { m_ast_owned = true; m_language_options_up = std::make_unique<LangOptions>(); - ParseLangArgs(*m_language_options_up, clang::Language::ObjCXX, - GetTargetTriple()); + ParseLangArgs(*m_language_options_up, ArchSpec(GetTargetTriple())); m_identifier_table_up = std::make_unique<IdentifierTable>(*m_language_options_up, nullptr); @@ -904,8 +843,11 @@ lldb::BasicType TypeSystemClang::GetBasicTypeEnumeration(llvm::StringRef name) { {"__int128_t", eBasicTypeInt128}, {"__uint128_t", eBasicTypeUnsignedInt128}, - // Miscellaneous + // "bool" {"bool", eBasicTypeBool}, + {"_Bool", eBasicTypeBool}, + + // Miscellaneous {"float", eBasicTypeFloat}, {"double", eBasicTypeDouble}, {"long double", eBasicTypeLongDouble}, @@ -1211,6 +1153,8 @@ CompilerType TypeSystemClang::GetTypeForDecl(clang::NamedDecl *decl) { return GetTypeForDecl(interface_decl); if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl)) return GetTypeForDecl(tag_decl); + if (clang::ValueDecl *value_decl = llvm::dyn_cast<clang::ValueDecl>(decl)) + return GetTypeForDecl(value_decl); return CompilerType(); } @@ -1222,6 +1166,10 @@ CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) { return GetType(getASTContext().getObjCInterfaceType(decl)); } +CompilerType TypeSystemClang::GetTypeForDecl(clang::ValueDecl *value_decl) { + return GetType(value_decl->getType()); +} + #pragma mark Structure, Unions, Classes void TypeSystemClang::SetOwningModule(clang::Decl *decl, @@ -1293,7 +1241,7 @@ CompilerType TypeSystemClang::CreateRecordType( // complete definition just in case. bool has_name = !name.empty(); - CXXRecordDecl *decl = CXXRecordDecl::CreateDeserialized(ast, 0); + CXXRecordDecl *decl = CXXRecordDecl::CreateDeserialized(ast, GlobalDeclID()); decl->setTagKind(static_cast<TagDecl::TagKind>(kind)); decl->setDeclContext(decl_ctx); if (has_name) @@ -1465,7 +1413,7 @@ clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); FunctionTemplateDecl *func_tmpl_decl = - FunctionTemplateDecl::CreateDeserialized(ast, 0); + FunctionTemplateDecl::CreateDeserialized(ast, GlobalDeclID()); func_tmpl_decl->setDeclContext(decl_ctx); func_tmpl_decl->setLocation(func_decl->getLocation()); func_tmpl_decl->setDeclName(func_decl->getDeclName()); @@ -1627,7 +1575,8 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); - CXXRecordDecl *template_cxx_decl = CXXRecordDecl::CreateDeserialized(ast, 0); + CXXRecordDecl *template_cxx_decl = + CXXRecordDecl::CreateDeserialized(ast, GlobalDeclID()); template_cxx_decl->setTagKind(static_cast<TagDecl::TagKind>(kind)); // What decl context do we use here? TU? The actual decl context? template_cxx_decl->setDeclContext(decl_ctx); @@ -1644,7 +1593,8 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( // template_cxx_decl->startDefinition(); // template_cxx_decl->completeDefinition(); - class_template_decl = ClassTemplateDecl::CreateDeserialized(ast, 0); + class_template_decl = + ClassTemplateDecl::CreateDeserialized(ast, GlobalDeclID()); // What decl context do we use here? TU? The actual decl context? class_template_decl->setDeclContext(decl_ctx); class_template_decl->setDeclName(decl_name); @@ -1681,10 +1631,11 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) { // type that includes a template template argument. Only the name matters for // this purpose, so we use dummy values for the other characteristics of the // type. - return TemplateTemplateParmDecl::Create( - ast, decl_ctx, SourceLocation(), - /*Depth*/ 0, /*Position*/ 0, - /*IsParameterPack*/ false, &identifier_info, template_param_list); + return TemplateTemplateParmDecl::Create(ast, decl_ctx, SourceLocation(), + /*Depth=*/0, /*Position=*/0, + /*IsParameterPack=*/false, + &identifier_info, /*Typename=*/false, + template_param_list); } ClassTemplateSpecializationDecl * @@ -1704,7 +1655,7 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl( ast, template_param_infos.GetParameterPackArgs()); } ClassTemplateSpecializationDecl *class_template_specialization_decl = - ClassTemplateSpecializationDecl::CreateDeserialized(ast, 0); + ClassTemplateSpecializationDecl::CreateDeserialized(ast, GlobalDeclID()); class_template_specialization_decl->setTagKind( static_cast<TagDecl::TagKind>(kind)); class_template_specialization_decl->setDeclContext(decl_ctx); @@ -1854,7 +1805,8 @@ CompilerType TypeSystemClang::CreateObjCClass( if (!decl_ctx) decl_ctx = ast.getTranslationUnitDecl(); - ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); + ObjCInterfaceDecl *decl = + ObjCInterfaceDecl::CreateDeserialized(ast, GlobalDeclID()); decl->setDeclContext(decl_ctx); decl->setDeclName(&ast.Idents.get(name)); /*isForwardDecl,*/ @@ -1962,7 +1914,7 @@ TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx, OptionalClangModuleID owning_module) { if (ctx) { clang::BlockDecl *decl = - clang::BlockDecl::CreateDeserialized(getASTContext(), 0); + clang::BlockDecl::CreateDeserialized(getASTContext(), GlobalDeclID()); decl->setDeclContext(ctx); ctx->addDecl(decl); SetOwningModule(decl, owning_module); @@ -2031,7 +1983,7 @@ clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( const char *name, clang::QualType type) { if (decl_context) { clang::VarDecl *var_decl = - clang::VarDecl::CreateDeserialized(getASTContext(), 0); + clang::VarDecl::CreateDeserialized(getASTContext(), GlobalDeclID()); var_decl->setDeclContext(decl_context); if (name && name[0]) var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); @@ -2191,7 +2143,7 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclarationName declarationName = GetDeclarationName(name, function_clang_type); - func_decl = FunctionDecl::CreateDeserialized(ast, 0); + func_decl = FunctionDecl::CreateDeserialized(ast, GlobalDeclID()); func_decl->setDeclContext(decl_ctx); func_decl->setDeclName(declarationName); func_decl->setType(ClangUtil::GetQualType(function_clang_type)); @@ -2252,7 +2204,7 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( const char *name, const CompilerType ¶m_type, int storage, bool add_decl) { ASTContext &ast = getASTContext(); - auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); + auto *decl = ParmVarDecl::CreateDeserialized(ast, GlobalDeclID()); decl->setDeclContext(decl_ctx); if (name && name[0]) decl->setDeclName(&ast.Idents.get(name)); @@ -2357,7 +2309,7 @@ CompilerType TypeSystemClang::CreateEnumerationType( // TODO: ask about these... // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::CreateDeserialized(ast, 0); + EnumDecl *enum_decl = EnumDecl::CreateDeserialized(ast, GlobalDeclID()); enum_decl->setDeclContext(decl_ctx); if (!name.empty()) enum_decl->setDeclName(&ast.Idents.get(name)); @@ -2622,6 +2574,128 @@ TypeSystemClang::GetDeclContextForType(clang::QualType type) { return nullptr; } +/// Returns the clang::RecordType of the specified \ref qual_type. This +/// function will try to complete the type if necessary (and allowed +/// by the specified \ref allow_completion). If we fail to return a *complete* +/// type, returns nullptr. +static const clang::RecordType *GetCompleteRecordType(clang::ASTContext *ast, + clang::QualType qual_type, + bool allow_completion) { + assert(qual_type->isRecordType()); + + const auto *tag_type = llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + + clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + + // RecordType with no way of completing it, return the plain + // TagType. + if (!cxx_record_decl || !cxx_record_decl->hasExternalLexicalStorage()) + return tag_type; + + const bool is_complete = cxx_record_decl->isCompleteDefinition(); + const bool fields_loaded = + cxx_record_decl->hasLoadedFieldsFromExternalStorage(); + + // Already completed this type, nothing to be done. + if (is_complete && fields_loaded) + return tag_type; + + if (!allow_completion) + return nullptr; + + // Call the field_begin() accessor to for it to use the external source + // to load the fields... + // + // TODO: if we need to complete the type but have no external source, + // shouldn't we error out instead? + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) { + external_ast_source->CompleteType(cxx_record_decl); + if (cxx_record_decl->isCompleteDefinition()) { + cxx_record_decl->field_begin(); + cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); + } + } + + return tag_type; +} + +/// Returns the clang::EnumType of the specified \ref qual_type. This +/// function will try to complete the type if necessary (and allowed +/// by the specified \ref allow_completion). If we fail to return a *complete* +/// type, returns nullptr. +static const clang::EnumType *GetCompleteEnumType(clang::ASTContext *ast, + clang::QualType qual_type, + bool allow_completion) { + assert(qual_type->isEnumeralType()); + assert(ast); + + const clang::EnumType *enum_type = + llvm::cast<clang::EnumType>(qual_type.getTypePtr()); + + auto *tag_decl = enum_type->getAsTagDecl(); + assert(tag_decl); + + // Already completed, nothing to be done. + if (tag_decl->getDefinition()) + return enum_type; + + if (!allow_completion) + return nullptr; + + // No definition but can't complete it, error out. + if (!tag_decl->hasExternalLexicalStorage()) + return nullptr; + + // We can't complete the type without an external source. + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (!external_ast_source) + return nullptr; + + external_ast_source->CompleteType(tag_decl); + return enum_type; +} + +/// Returns the clang::ObjCObjectType of the specified \ref qual_type. This +/// function will try to complete the type if necessary (and allowed +/// by the specified \ref allow_completion). If we fail to return a *complete* +/// type, returns nullptr. +static const clang::ObjCObjectType * +GetCompleteObjCObjectType(clang::ASTContext *ast, QualType qual_type, + bool allow_completion) { + assert(qual_type->isObjCObjectType()); + assert(ast); + + const clang::ObjCObjectType *objc_class_type = + llvm::cast<clang::ObjCObjectType>(qual_type); + + clang::ObjCInterfaceDecl *class_interface_decl = + objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added + // ASTContext because it only supports TagDecl objects right now... + if (!class_interface_decl) + return objc_class_type; + + // Already complete, nothing to be done. + if (class_interface_decl->getDefinition()) + return objc_class_type; + + if (!allow_completion) + return nullptr; + + // No definition but can't complete it, error out. + if (!class_interface_decl->hasExternalLexicalStorage()) + return nullptr; + + // We can't complete the type without an external source. + clang::ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (!external_ast_source) + return nullptr; + + external_ast_source->CompleteType(class_interface_decl); + return objc_class_type; +} + static bool GetCompleteQualType(clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion = true) { @@ -2639,92 +2713,26 @@ static bool GetCompleteQualType(clang::ASTContext *ast, allow_completion); } break; case clang::Type::Record: { - clang::CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); - if (cxx_record_decl) { - if (cxx_record_decl->hasExternalLexicalStorage()) { - const bool is_complete = cxx_record_decl->isCompleteDefinition(); - const bool fields_loaded = - cxx_record_decl->hasLoadedFieldsFromExternalStorage(); - if (is_complete && fields_loaded) - return true; + if (const auto *RT = + GetCompleteRecordType(ast, qual_type, allow_completion)) + return !RT->isIncompleteType(); - if (!allow_completion) - return false; - - // Call the field_begin() accessor to for it to use the external source - // to load the fields... - clang::ExternalASTSource *external_ast_source = - ast->getExternalSource(); - if (external_ast_source) { - external_ast_source->CompleteType(cxx_record_decl); - if (cxx_record_decl->isCompleteDefinition()) { - cxx_record_decl->field_begin(); - cxx_record_decl->setHasLoadedFieldsFromExternalStorage(true); - } - } - } - } - const clang::TagType *tag_type = - llvm::cast<clang::TagType>(qual_type.getTypePtr()); - return !tag_type->isIncompleteType(); + return false; } break; case clang::Type::Enum: { - const clang::TagType *tag_type = - llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()); - if (tag_type) { - clang::TagDecl *tag_decl = tag_type->getDecl(); - if (tag_decl) { - if (tag_decl->getDefinition()) - return true; - - if (!allow_completion) - return false; - - if (tag_decl->hasExternalLexicalStorage()) { - if (ast) { - clang::ExternalASTSource *external_ast_source = - ast->getExternalSource(); - if (external_ast_source) { - external_ast_source->CompleteType(tag_decl); - return !tag_type->isIncompleteType(); - } - } - } - return false; - } - } + if (const auto *ET = GetCompleteEnumType(ast, qual_type, allow_completion)) + return !ET->isIncompleteType(); + return false; } break; case clang::Type::ObjCObject: case clang::Type::ObjCInterface: { - const clang::ObjCObjectType *objc_class_type = - llvm::dyn_cast<clang::ObjCObjectType>(qual_type); - if (objc_class_type) { - clang::ObjCInterfaceDecl *class_interface_decl = - objc_class_type->getInterface(); - // We currently can't complete objective C types through the newly added - // ASTContext because it only supports TagDecl objects right now... - if (class_interface_decl) { - if (class_interface_decl->getDefinition()) - return true; - - if (!allow_completion) - return false; + if (const auto *OT = + GetCompleteObjCObjectType(ast, qual_type, allow_completion)) + return !OT->isIncompleteType(); - if (class_interface_decl->hasExternalLexicalStorage()) { - if (ast) { - clang::ExternalASTSource *external_ast_source = - ast->getExternalSource(); - if (external_ast_source) { - external_ast_source->CompleteType(class_interface_decl); - return !objc_class_type->isIncompleteType(); - } - } - } - return false; - } - } + return false; } break; case clang::Type::Attributed: @@ -2975,6 +2983,35 @@ bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type, return false; } +unsigned TypeSystemClang::GetPtrAuthKey(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.getKey(); + } + return 0; +} + +unsigned +TypeSystemClang::GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.getExtraDiscriminator(); + } + return 0; +} + +bool TypeSystemClang::GetPtrAuthAddressDiversity( + lldb::opaque_compiler_type_t type) { + if (type) { + clang::QualType qual_type(GetCanonicalQualType(type)); + if (auto pointer_auth = qual_type.getPointerAuth()) + return pointer_auth.isAddressDiscriminated(); + } + return false; +} + bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type) { auto isFunctionType = [&](clang::QualType qual_type) { return qual_type->isFunctionType(); @@ -4074,6 +4111,7 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { switch (qual_type->getTypeClass()) { case clang::Type::Atomic: case clang::Type::Auto: + case clang::Type::CountAttributed: case clang::Type::Decltype: case clang::Type::Elaborated: case clang::Type::Paren: @@ -4095,6 +4133,8 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { return lldb::eTypeClassArray; case clang::Type::DependentSizedArray: return lldb::eTypeClassArray; + case clang::Type::ArrayParameter: + return lldb::eTypeClassArray; case clang::Type::DependentSizedExtVector: return lldb::eTypeClassVector; case clang::Type::DependentVector: @@ -4189,6 +4229,10 @@ TypeSystemClang::GetTypeClass(lldb::opaque_compiler_type_t type) { case clang::Type::ConstantMatrix: case clang::Type::DependentSizedMatrix: break; + + // We don't handle pack indexing yet + case clang::Type::PackIndexing: + break; } // We don't know hot to display this type... return lldb::eTypeClassOther; @@ -4557,6 +4601,19 @@ TypeSystemClang::AddConstModifier(lldb::opaque_compiler_type_t type) { } CompilerType +TypeSystemClang::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) { + if (type) { + clang::ASTContext &clang_ast = getASTContext(); + auto pauth = PointerAuthQualifier::fromOpaqueValue(payload); + clang::QualType result = + clang_ast.getPointerAuthType(GetQualType(type), pauth); + return GetType(result); + } + return CompilerType(); +} + +CompilerType TypeSystemClang::AddVolatileModifier(lldb::opaque_compiler_type_t type) { if (type) { clang::QualType result(GetQualType(type)); @@ -4589,7 +4646,7 @@ CompilerType TypeSystemClang::CreateTypedef( decl_ctx = getASTContext().getTranslationUnitDecl(); clang::TypedefDecl *decl = - clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + clang::TypedefDecl::CreateDeserialized(clang_ast, GlobalDeclID()); decl->setDeclContext(decl_ctx); decl->setDeclName(&clang_ast.Idents.get(typedef_name)); decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); @@ -4687,11 +4744,11 @@ TypeSystemClang::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContext exe_ctx(exe_scope); Process *process = exe_ctx.GetProcessPtr(); if (process) { - ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process); - if (objc_runtime) { - uint64_t bit_size = 0; - if (objc_runtime->GetTypeBitSize(GetType(qual_type), bit_size)) - return bit_size; + if (ObjCLanguageRuntime *objc_runtime = + ObjCLanguageRuntime::Get(*process)) { + if (std::optional<uint64_t> bit_size = + objc_runtime->GetTypeBitSize(GetType(qual_type))) + return *bit_size; } } else { static bool g_printed = false; @@ -4751,6 +4808,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, switch (qual_type->getTypeClass()) { case clang::Type::Atomic: case clang::Type::Auto: + case clang::Type::CountAttributed: case clang::Type::Decltype: case clang::Type::Elaborated: case clang::Type::Paren: @@ -4769,6 +4827,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: @@ -4904,7 +4963,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::Kind::OCLQueue: case clang::BuiltinType::Kind::OCLReserveID: case clang::BuiltinType::Kind::OCLSampler: - case clang::BuiltinType::Kind::OMPArraySection: + case clang::BuiltinType::Kind::ArraySection: case clang::BuiltinType::Kind::OMPArrayShaping: case clang::BuiltinType::Kind::OMPIterator: case clang::BuiltinType::Kind::Overload: @@ -4997,6 +5056,14 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::IncompleteMatrixIdx: break; + + case clang::BuiltinType::UnresolvedTemplate: + break; + + // AMD GPU builtin types. +#define AMDGPU_TYPE(Name, Id, SingletonId) case clang::BuiltinType::Id: +#include "clang/Basic/AMDGPUTypes.def" + break; } break; // All pointer types are represented as unsigned integer encodings. We may @@ -5066,6 +5133,10 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::ConstantMatrix: case clang::Type::DependentSizedMatrix: break; + + // We don't handle pack indexing yet + case clang::Type::PackIndexing: + break; } count = 0; return lldb::eEncodingInvalid; @@ -5080,6 +5151,7 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { switch (qual_type->getTypeClass()) { case clang::Type::Atomic: case clang::Type::Auto: + case clang::Type::CountAttributed: case clang::Type::Decltype: case clang::Type::Elaborated: case clang::Type::Paren: @@ -5097,6 +5169,7 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::Type::IncompleteArray: case clang::Type::VariableArray: + case clang::Type::ArrayParameter: break; case clang::Type::ConstantArray: @@ -5221,6 +5294,10 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::Type::ConstantMatrix: case clang::Type::DependentSizedMatrix: break; + + // We don't handle pack indexing yet + case clang::Type::PackIndexing: + break; } // We don't know hot to display this type... return lldb::eFormatBytes; @@ -5251,11 +5328,12 @@ GetDynamicArrayInfo(TypeSystemClang &ast, SymbolFile *sym_file, return std::nullopt; } -uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, - bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) { +llvm::Expected<uint32_t> +TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) { if (!type) - return 0; + return llvm::createStringError("invalid clang type"); uint32_t num_children = 0; clang::QualType qual_type(RemoveWrappingTypes(GetQualType(type))); @@ -5312,9 +5390,10 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, } num_children += std::distance(record_decl->field_begin(), record_decl->field_end()); - } + } else + return llvm::createStringError( + "incomplete type \"" + GetDisplayTypeName(type).GetString() + "\""); break; - case clang::Type::ObjCObject: case clang::Type::ObjCInterface: if (GetCompleteQualType(&getASTContext(), qual_type)) { @@ -5349,9 +5428,13 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, CompilerType pointee_clang_type(GetPointeeType(type)); uint32_t num_pointee_children = 0; - if (pointee_clang_type.IsAggregateType()) - num_pointee_children = + if (pointee_clang_type.IsAggregateType()) { + auto num_children_or_err = pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx); + if (!num_children_or_err) + return num_children_or_err; + num_pointee_children = *num_children_or_err; + } // If this type points to a simple type, then it has 1 child if (num_pointee_children == 0) num_children = 1; @@ -5385,9 +5468,13 @@ uint32_t TypeSystemClang::GetNumChildren(lldb::opaque_compiler_type_t type, clang::QualType pointee_type(pointer_type->getPointeeType()); CompilerType pointee_clang_type(GetType(pointee_type)); uint32_t num_pointee_children = 0; - if (pointee_clang_type.IsAggregateType()) - num_pointee_children = + if (pointee_clang_type.IsAggregateType()) { + auto num_children_or_err = pointee_clang_type.GetNumChildren(omit_empty_base_classes, exe_ctx); + if (!num_children_or_err) + return num_children_or_err; + num_pointee_children = *num_children_or_err; + } if (num_pointee_children == 0) { // We have a pointer to a pointee type that claims it has no children. We // will want to look at @@ -5934,6 +6021,36 @@ CompilerType TypeSystemClang::GetVirtualBaseClassAtIndex( return CompilerType(); } +CompilerDecl +TypeSystemClang::GetStaticFieldWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) { + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + switch (qual_type->getTypeClass()) { + case clang::Type::Record: { + if (!GetCompleteType(type)) + return CompilerDecl(); + + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + + clang::DeclarationName decl_name(&getASTContext().Idents.get(name)); + for (NamedDecl *decl : record_decl->lookup(decl_name)) { + auto *var_decl = dyn_cast<clang::VarDecl>(decl); + if (!var_decl || var_decl->getStorageClass() != clang::SC_Static) + continue; + + return CompilerDecl(this, var_decl); + } + break; + } + + default: + break; + } + return CompilerDecl(); +} + // If a pointer to a pointee type (the clang_type arg) says that it has no // children, then we either need to trust it, or override it and return a // different result. For example, an "int *" has one child that is an integer, @@ -6004,7 +6121,7 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { case clang::BuiltinType::ARCUnbridgedCast: case clang::BuiltinType::PseudoObject: case clang::BuiltinType::BuiltinFn: - case clang::BuiltinType::OMPArraySection: + case clang::BuiltinType::ArraySection: return 1; default: return 0; @@ -6072,7 +6189,7 @@ uint32_t TypeSystemClang::GetNumPointeeChildren(clang::QualType type) { return 0; } -CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( +llvm::Expected<CompilerType> TypeSystemClang::GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, @@ -6096,8 +6213,12 @@ CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( child_is_base_class = false; language_flags = 0; - const bool idx_is_valid = - idx < GetNumChildren(type, omit_empty_base_classes, exe_ctx); + auto num_children_or_err = + GetNumChildren(type, omit_empty_base_classes, exe_ctx); + if (!num_children_or_err) + return num_children_or_err.takeError(); + + const bool idx_is_valid = idx < *num_children_or_err; int32_t bit_offset; switch (parent_type_class) { case clang::Type::Builtin: @@ -6177,7 +6298,8 @@ CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( std::optional<uint64_t> size = base_class_clang_type.GetBitSize(get_exe_scope()); if (!size) - return {}; + return llvm::createStringError("no size info for base class"); + uint64_t base_class_clang_type_bit_size = *size; // Base classes bit sizes should be a multiple of 8 bits in size @@ -6209,7 +6331,8 @@ CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( std::optional<uint64_t> size = field_clang_type.GetByteSize(get_exe_scope()); if (!size) - return {}; + return llvm::createStringError("no size info for field"); + child_byte_size = *size; const uint32_t child_bit_size = child_byte_size * 8; @@ -6253,8 +6376,10 @@ CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( CompilerType base_class_clang_type = GetType(getASTContext().getObjCInterfaceType( superclass_interface_decl)); - if (base_class_clang_type.GetNumChildren(omit_empty_base_classes, - exe_ctx) > 0) { + if (llvm::expectedToStdOptional( + base_class_clang_type.GetNumChildren( + omit_empty_base_classes, exe_ctx)) + .value_or(0) > 0) { if (idx == 0) { clang::QualType ivar_qual_type( getASTContext().getObjCInterfaceType( @@ -6625,7 +6750,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( return child_indexes.size(); child_indexes.pop_back(); - } else if (field_name.equals(name)) { + } else if (field_name == name) { // We have to add on the number of base classes to this index! child_indexes.push_back( child_idx + TypeSystemClang::GetNumBaseClasses( @@ -6712,7 +6837,7 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( ivar_pos != ivar_end; ++ivar_pos, ++child_idx) { const clang::ObjCIvarDecl *ivar_decl = *ivar_pos; - if (ivar_decl->getName().equals(name_sref)) { + if (ivar_decl->getName() == name_sref) { if ((!omit_empty_base_classes && superclass_interface_decl) || (omit_empty_base_classes && ObjCDeclHasIVars(superclass_interface_decl, true))) @@ -6881,7 +7006,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++child_idx) { - if (field->getName().equals(name)) + if (field->getName() == name) return child_idx; } } @@ -6908,7 +7033,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, ivar_pos != ivar_end; ++ivar_pos, ++child_idx) { const clang::ObjCIvarDecl *ivar_decl = *ivar_pos; - if (ivar_decl->getName().equals(name)) { + if (ivar_decl->getName() == name) { if ((!omit_empty_base_classes && superclass_interface_decl) || (omit_empty_base_classes && ObjCDeclHasIVars(superclass_interface_decl, true))) @@ -6919,7 +7044,7 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, } if (superclass_interface_decl) { - if (superclass_interface_decl->getName().equals(name)) + if (superclass_interface_decl->getName() == name) return 0; } } @@ -7022,6 +7147,38 @@ TypeSystemClang::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, return UINT32_MAX; } +CompilerType +TypeSystemClang::GetDirectNestedTypeWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) { + if (!type || name.empty()) + return CompilerType(); + + clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + + switch (type_class) { + case clang::Type::Record: { + if (!GetCompleteType(type)) + return CompilerType(); + const clang::RecordType *record_type = + llvm::cast<clang::RecordType>(qual_type.getTypePtr()); + const clang::RecordDecl *record_decl = record_type->getDecl(); + + clang::DeclarationName decl_name(&getASTContext().Idents.get(name)); + for (NamedDecl *decl : record_decl->lookup(decl_name)) { + if (auto *tag_decl = dyn_cast<clang::TagDecl>(decl)) + return GetType(getASTContext().getTagDeclType(tag_decl)); + if (auto *typedef_decl = dyn_cast<clang::TypedefNameDecl>(decl)) + return GetType(getASTContext().getTypedefType(typedef_decl)); + } + break; + } + default: + break; + } + return CompilerType(); +} + bool TypeSystemClang::IsTemplateType(lldb::opaque_compiler_type_t type) { if (!type) return false; @@ -7283,7 +7440,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); if (record_decl) { - field = clang::FieldDecl::CreateDeserialized(clang_ast, 0); + field = clang::FieldDecl::CreateDeserialized(clang_ast, GlobalDeclID()); field->setDeclContext(record_decl); field->setDeclName(ident); field->setType(ClangUtil::GetQualType(field_clang_type)); @@ -7330,7 +7487,8 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field_clang_type.GetCompleteType(); - auto *ivar = clang::ObjCIvarDecl::CreateDeserialized(clang_ast, 0); + auto *ivar = + clang::ObjCIvarDecl::CreateDeserialized(clang_ast, GlobalDeclID()); ivar->setDeclContext(class_interface_decl); ivar->setDeclName(ident); ivar->setType(ClangUtil::GetQualType(field_clang_type)); @@ -7496,7 +7654,8 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( if (!name.empty()) ident = &ast->getASTContext().Idents.get(name); - var_decl = clang::VarDecl::CreateDeserialized(ast->getASTContext(), 0); + var_decl = + clang::VarDecl::CreateDeserialized(ast->getASTContext(), GlobalDeclID()); var_decl->setDeclContext(record_decl); var_decl->setDeclName(ident); var_decl->setType(ClangUtil::GetQualType(var_type)); @@ -7597,8 +7756,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( : clang::ExplicitSpecKind::ResolvedFalse); if (name.starts_with("~")) { - cxx_dtor_decl = - clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0); + cxx_dtor_decl = clang::CXXDestructorDecl::CreateDeserialized( + getASTContext(), GlobalDeclID()); cxx_dtor_decl->setDeclContext(cxx_record_decl); cxx_dtor_decl->setDeclName( getASTContext().DeclarationNames.getCXXDestructorName( @@ -7610,7 +7769,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl = cxx_dtor_decl; } else if (decl_name == cxx_record_decl->getDeclName()) { cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( - getASTContext(), 0, 0); + getASTContext(), GlobalDeclID(), 0); cxx_ctor_decl->setDeclContext(cxx_record_decl); cxx_ctor_decl->setDeclName( getASTContext().DeclarationNames.getCXXConstructorName( @@ -7636,8 +7795,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( is_method, op_kind, num_params)) return nullptr; - cxx_method_decl = - clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl = clang::CXXMethodDecl::CreateDeserialized( + getASTContext(), GlobalDeclID()); cxx_method_decl->setDeclContext(cxx_record_decl); cxx_method_decl->setDeclName( getASTContext().DeclarationNames.getCXXOperatorName(op_kind)); @@ -7648,7 +7807,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( } else if (num_params == 0) { // Conversion operators don't take params... auto *cxx_conversion_decl = - clang::CXXConversionDecl::CreateDeserialized(getASTContext(), 0); + clang::CXXConversionDecl::CreateDeserialized(getASTContext(), + GlobalDeclID()); cxx_conversion_decl->setDeclContext(cxx_record_decl); cxx_conversion_decl->setDeclName( getASTContext().DeclarationNames.getCXXConversionFunctionName( @@ -7663,8 +7823,8 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( } if (cxx_method_decl == nullptr) { - cxx_method_decl = - clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl = clang::CXXMethodDecl::CreateDeserialized( + getASTContext(), GlobalDeclID()); cxx_method_decl->setDeclContext(cxx_record_decl); cxx_method_decl->setDeclName(decl_name); cxx_method_decl->setType(method_qual_type); @@ -7847,7 +8007,7 @@ bool TypeSystemClang::AddObjCClassProperty( ClangUtil::GetQualType(property_clang_type)); clang::ObjCPropertyDecl *property_decl = - clang::ObjCPropertyDecl::CreateDeserialized(clang_ast, 0); + clang::ObjCPropertyDecl::CreateDeserialized(clang_ast, GlobalDeclID()); property_decl->setDeclContext(class_interface_decl); property_decl->setDeclName(&clang_ast.Idents.get(property_name)); property_decl->setType(ivar_decl @@ -7869,14 +8029,14 @@ bool TypeSystemClang::AddObjCClassProperty( if (property_setter_name) { std::string property_setter_no_colon(property_setter_name, strlen(property_setter_name) - 1); - clang::IdentifierInfo *setter_ident = + const clang::IdentifierInfo *setter_ident = &clang_ast.Idents.get(property_setter_no_colon); setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident); } else if (!(property_attributes & DW_APPLE_PROPERTY_readonly)) { std::string setter_sel_string("set"); setter_sel_string.push_back(::toupper(property_name[0])); setter_sel_string.append(&property_name[1]); - clang::IdentifierInfo *setter_ident = + const clang::IdentifierInfo *setter_ident = &clang_ast.Idents.get(setter_sel_string); setter_sel = clang_ast.Selectors.getSelector(1, &setter_ident); } @@ -7884,11 +8044,12 @@ bool TypeSystemClang::AddObjCClassProperty( property_decl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter); if (property_getter_name != nullptr) { - clang::IdentifierInfo *getter_ident = + const clang::IdentifierInfo *getter_ident = &clang_ast.Idents.get(property_getter_name); getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident); } else { - clang::IdentifierInfo *getter_ident = &clang_ast.Idents.get(property_name); + const clang::IdentifierInfo *getter_ident = + &clang_ast.Idents.get(property_name); getter_sel = clang_ast.Selectors.getSelector(0, &getter_ident); } property_decl->setGetterName(getter_sel); @@ -7935,7 +8096,8 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; - getter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + getter = + clang::ObjCMethodDecl::CreateDeserialized(clang_ast, GlobalDeclID()); getter->setDeclName(getter_sel); getter->setReturnType(ClangUtil::GetQualType(property_clang_type_to_access)); getter->setDeclContext(class_interface_decl); @@ -7977,7 +8139,8 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCImplementationControl::None; const bool HasRelatedResultType = false; - setter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + setter = + clang::ObjCMethodDecl::CreateDeserialized(clang_ast, GlobalDeclID()); setter->setDeclName(setter_sel); setter->setReturnType(result_type); setter->setDeclContext(class_interface_decl); @@ -8050,7 +8213,7 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( return nullptr; selector_start++; - llvm::SmallVector<clang::IdentifierInfo *, 12> selector_idents; + llvm::SmallVector<const clang::IdentifierInfo *, 12> selector_idents; size_t len = 0; const char *start; @@ -8105,7 +8268,8 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( return nullptr; // some debug information is corrupt. We are not going to // deal with it. - auto *objc_method_decl = clang::ObjCMethodDecl::CreateDeserialized(ast, 0); + auto *objc_method_decl = + clang::ObjCMethodDecl::CreateDeserialized(ast, GlobalDeclID()); objc_method_decl->setDeclName(method_selector); objc_method_decl->setReturnType(method_function_prototype->getReturnType()); objc_method_decl->setDeclContext( @@ -8351,7 +8515,8 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( return nullptr; clang::EnumConstantDecl *enumerator_decl = - clang::EnumConstantDecl::CreateDeserialized(getASTContext(), 0); + clang::EnumConstantDecl::CreateDeserialized(getASTContext(), + GlobalDeclID()); enumerator_decl->setDeclContext(enutype->getDecl()); if (name && name[0]) enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); @@ -8474,8 +8639,13 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, const clang::EnumDecl *enum_decl = enutype->getDecl(); assert(enum_decl); lldb::offset_t offset = byte_offset; - const uint64_t enum_svalue = data.GetMaxS64Bitfield( - &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + bool qual_type_is_signed = qual_type->isSignedIntegerOrEnumerationType(); + const uint64_t enum_svalue = + qual_type_is_signed + ? data.GetMaxS64Bitfield(&offset, byte_size, bitfield_bit_size, + bitfield_bit_offset) + : data.GetMaxU64Bitfield(&offset, byte_size, bitfield_bit_size, + bitfield_bit_offset); bool can_be_bitfield = true; uint64_t covered_bits = 0; int num_enumerators = 0; @@ -8486,17 +8656,25 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, // every enumerator is either a one bit value or a superset of the previous // enumerators. Also 0 doesn't make sense when the enumerators are used as // flags. - for (auto *enumerator : enum_decl->enumerators()) { - uint64_t val = enumerator->getInitVal().getSExtValue(); - val = llvm::SignExtend64(val, 8*byte_size); - if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0) - can_be_bitfield = false; - covered_bits |= val; - ++num_enumerators; - if (val == enum_svalue) { - // Found an exact match, that's all we need to do. - s.PutCString(enumerator->getNameAsString()); - return true; + clang::EnumDecl::enumerator_range enumerators = enum_decl->enumerators(); + if (enumerators.empty()) + can_be_bitfield = false; + else { + for (auto *enumerator : enumerators) { + llvm::APSInt init_val = enumerator->getInitVal(); + uint64_t val = qual_type_is_signed ? init_val.getSExtValue() + : init_val.getZExtValue(); + if (qual_type_is_signed) + val = llvm::SignExtend64(val, 8 * byte_size); + if (llvm::popcount(val) != 1 && (val & ~covered_bits) != 0) + can_be_bitfield = false; + covered_bits |= val; + ++num_enumerators; + if (val == enum_svalue) { + // Found an exact match, that's all we need to do. + s.PutCString(enumerator->getNameAsString()); + return true; + } } } @@ -8508,13 +8686,20 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, // No exact match, but we don't think this is a bitfield. Print the value as // decimal. if (!can_be_bitfield) { - if (qual_type->isSignedIntegerOrEnumerationType()) + if (qual_type_is_signed) s.Printf("%" PRIi64, enum_svalue); else s.Printf("%" PRIu64, enum_uvalue); return true; } + if (!enum_uvalue) { + // This is a bitfield enum, but the value is 0 so we know it won't match + // with any of the enumerators. + s.Printf("0x%" PRIx64, enum_uvalue); + return true; + } + uint64_t remaining_value = enum_uvalue; std::vector<std::pair<uint64_t, llvm::StringRef>> values; values.reserve(num_enumerators); @@ -8539,7 +8724,8 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s, s.PutCString(" | "); } - // If there is a remainder that is not covered by the value, print it as hex. + // If there is a remainder that is not covered by the value, print it as + // hex. if (remaining_value) s.Printf("0x%" PRIx64, remaining_value); @@ -9012,10 +9198,8 @@ static CompilerContextKind GetCompilerKind(clang::Decl::Kind clang_kind, if (decl_ctx) { if (decl_ctx->isFunctionOrMethod()) return CompilerContextKind::Function; - else if (decl_ctx->isRecord()) - return (CompilerContextKind)((uint16_t)CompilerContextKind::Class | - (uint16_t)CompilerContextKind::Struct | - (uint16_t)CompilerContextKind::Union); + if (decl_ctx->isRecord()) + return CompilerContextKind::ClassOrStruct | CompilerContextKind::Union; } break; } @@ -9072,6 +9256,21 @@ CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl, return CompilerType(); } +Scalar TypeSystemClang::DeclGetConstantValue(void *opaque_decl) { + clang::Decl *decl = static_cast<clang::Decl *>(opaque_decl); + clang::VarDecl *var_decl = llvm::dyn_cast<clang::VarDecl>(decl); + if (!var_decl) + return Scalar(); + clang::Expr *init_expr = var_decl->getInit(); + if (!init_expr) + return Scalar(); + std::optional<llvm::APSInt> value = + init_expr->getIntegerConstantExpr(getASTContext()); + if (!value) + return Scalar(); + return Scalar(*value); +} + // CompilerDeclContext functions std::vector<CompilerDecl> TypeSystemClang::DeclContextFindDeclByName( @@ -9113,15 +9312,14 @@ std::vector<CompilerDecl> TypeSystemClang::DeclContextFindDeclByName( if (clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(target)) { IdentifierInfo *ii = nd->getIdentifier(); - if (ii != nullptr && - ii->getName().equals(name.AsCString(nullptr))) + if (ii != nullptr && ii->getName() == name.AsCString(nullptr)) found_decls.push_back(GetCompilerDecl(nd)); } } } else if (clang::NamedDecl *nd = llvm::dyn_cast<clang::NamedDecl>(child)) { IdentifierInfo *ii = nd->getIdentifier(); - if (ii != nullptr && ii->getName().equals(name.AsCString(nullptr))) + if (ii != nullptr && ii->getName() == name.AsCString(nullptr)) found_decls.push_back(GetCompilerDecl(nd)); } } @@ -9231,7 +9429,7 @@ uint32_t TypeSystemClang::CountDeclLevels(clang::DeclContext *frame_decl_ctx, // Check names. IdentifierInfo *ii = nd->getIdentifier(); if (ii == nullptr || - !ii->getName().equals(child_name->AsCString(nullptr))) + ii->getName() != child_name->AsCString(nullptr)) continue; // Check types, if one was provided. if (child_type) { @@ -9257,8 +9455,14 @@ ConstString TypeSystemClang::DeclContextGetName(void *opaque_decl_ctx) { if (opaque_decl_ctx) { clang::NamedDecl *named_decl = llvm::dyn_cast<clang::NamedDecl>((clang::DeclContext *)opaque_decl_ctx); - if (named_decl) - return ConstString(named_decl->getName()); + if (named_decl) { + std::string name; + llvm::raw_string_ostream stream{name}; + auto policy = GetTypePrintingPolicy(); + policy.AlwaysIncludeTypeForTemplateArgument = true; + named_decl->getNameForDiagnostic(stream, policy, /*qualified=*/false); + return ConstString(name); + } } return ConstString(); } @@ -9305,14 +9509,24 @@ bool TypeSystemClang::DeclContextIsContainedInLookup( auto *decl_ctx = (clang::DeclContext *)opaque_decl_ctx; auto *other = (clang::DeclContext *)other_opaque_decl_ctx; + // If we have an inline or anonymous namespace, then the lookup of the + // parent context also includes those namespace contents. + auto is_transparent_lookup_allowed = [](clang::DeclContext *DC) { + if (DC->isInlineNamespace()) + return true; + + if (auto const *NS = dyn_cast<NamespaceDecl>(DC)) + return NS->isAnonymousNamespace(); + + return false; + }; + do { // A decl context always includes its own contents in its lookup. if (decl_ctx == other) return true; - - // If we have an inline namespace, then the lookup of the parent context - // also includes the inline namespace contents. - } while (other->isInlineNamespace() && (other = other->getParent())); + } while (is_transparent_lookup_allowed(other) && + (other = other->getParent())); return false; } @@ -9523,7 +9737,7 @@ void ScratchTypeSystemClang::Dump(llvm::raw_ostream &output) { } UserExpression *ScratchTypeSystemClang::GetUserExpression( - llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, + llvm::StringRef expr, llvm::StringRef prefix, SourceLanguage language, Expression::ResultType desired_type, const EvaluateExpressionOptions &options, ValueObject *ctx_obj) { TargetSP target_sp = m_target_wp.lock(); @@ -9630,3 +9844,9 @@ bool TypeSystemClang::SetDeclIsForcefullyCompleted(const clang::TagDecl *td) { metadata->SetIsForcefullyCompleted(); return true; } + +void TypeSystemClang::LogCreation() const { + if (auto *log = GetLog(LLDBLog::Expressions)) + LLDB_LOG(log, "Created new TypeSystem for (ASTContext*){0:x} '{1}'", + &getASTContext(), getDisplayName()); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 878ab8f01e61..68aaf3593e43 100644 --- a/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/contrib/llvm-project/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -22,6 +22,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTFwd.h" +#include "clang/AST/Decl.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/TargetInfo.h" @@ -66,11 +67,13 @@ public: /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { - /// The Layout is as follows: + /// The payload is used for typedefs and ptrauth types. + /// For typedefs, the Layout is as follows: /// \verbatim /// bit 0..30 ... Owning Module ID. /// bit 31 ...... IsCompleteObjCClass. /// \endverbatim + /// For ptrauth types, we store the PointerAuthQualifier as an opaque value. Type::Payload m_payload = 0; public: @@ -159,7 +162,7 @@ public: llvm::StringRef getDisplayName() const { return m_display_name; } /// Returns the clang::ASTContext instance managed by this TypeSystemClang. - clang::ASTContext &getASTContext(); + clang::ASTContext &getASTContext() const; clang::MangleContext *getMangleContext(); @@ -251,6 +254,8 @@ public: CompilerType GetTypeForDecl(clang::ObjCInterfaceDecl *objc_decl); + CompilerType GetTypeForDecl(clang::ValueDecl *value_decl); + template <typename RecordDeclType> CompilerType GetTypeForIdentifier(llvm::StringRef type_name, @@ -561,6 +566,8 @@ public: std::vector<lldb_private::CompilerContext> DeclGetCompilerContext(void *opaque_decl) override; + Scalar DeclGetConstantValue(void *opaque_decl) override; + CompilerType GetTypeForDecl(void *opaque_decl) override; // CompilerDeclContext override functions @@ -650,6 +657,10 @@ public: bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) override; + unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) override; + unsigned GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) override; + bool GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) override; + bool IsFunctionType(lldb::opaque_compiler_type_t type) override; uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, @@ -790,6 +801,9 @@ public: CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override; + CompilerType AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) override; + CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) override; CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override; @@ -835,9 +849,10 @@ public: GetTypeBitAlign(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; - uint32_t GetNumChildren(lldb::opaque_compiler_type_t type, - bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) override; + llvm::Expected<uint32_t> + GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) override; CompilerType GetBuiltinTypeByName(ConstString name) override; @@ -869,9 +884,12 @@ public: size_t idx, uint32_t *bit_offset_ptr) override; + CompilerDecl GetStaticFieldWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) override; + static uint32_t GetNumPointeeChildren(clang::QualType type); - CompilerType GetChildCompilerTypeAtIndex( + llvm::Expected<CompilerType> GetChildCompilerTypeAtIndex( lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, @@ -898,6 +916,9 @@ public: bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes) override; + CompilerType GetDirectNestedTypeWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name) override; + bool IsTemplateType(lldb::opaque_compiler_type_t type) override; size_t GetNumTemplateArguments(lldb::opaque_compiler_type_t type, @@ -1147,6 +1168,12 @@ private: bool IsTypeImpl(lldb::opaque_compiler_type_t type, llvm::function_ref<bool(clang::QualType)> predicate) const; + /// Emits information about this TypeSystem into the expression log. + /// + /// Helper method that is used in \ref TypeSystemClang::TypeSystemClang + /// on creation of a new instance. + void LogCreation() const; + // Classes that inherit from TypeSystemClang can see and modify these std::string m_target_triple; std::unique_ptr<clang::ASTContext> m_ast_up; @@ -1272,12 +1299,12 @@ public: /// \see lldb_private::TypeSystem::Dump void Dump(llvm::raw_ostream &output) override; - UserExpression * - GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix, - lldb::LanguageType language, - Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) override; + UserExpression *GetUserExpression(llvm::StringRef expr, + llvm::StringRef prefix, + SourceLanguage language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, + ValueObject *ctx_obj) override; FunctionCaller *GetFunctionCaller(const CompilerType &return_type, const Address &function_address, diff --git a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 7ff5cd2c23b0..49edd40544e3 100644 --- a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -83,7 +83,7 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( const uint32_t addr_byte_size = m_arch.GetAddressByteSize(); const bool show_address = true; const bool show_bytes = true; - const bool show_control_flow_kind = true; + const bool show_control_flow_kind = false; m_cfa_reg_info = *m_inst_emulator_up->GetRegisterInfo( unwind_plan.GetRegisterKind(), unwind_plan.GetInitialCFARegister()); m_fp_is_cfa = false; @@ -424,8 +424,6 @@ size_t UnwindAssemblyInstEmulation::WriteMemory( log->PutString(strm.GetString()); } - const bool cant_replace = false; - switch (context.type) { default: case EmulateInstruction::eContextInvalid: @@ -467,7 +465,7 @@ size_t UnwindAssemblyInstEmulation::WriteMemory( m_pushed_regs[reg_num] = addr; const int32_t offset = addr - m_initial_sp; m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset, - cant_replace); + /*can_replace=*/true); m_curr_row_modified = true; } } diff --git a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp index 2032c5a68d05..6bfaa54135a9 100644 --- a/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp +++ b/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp @@ -909,6 +909,9 @@ bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( if (!m_register_map_initialized) return false; + if (m_disasm_context == nullptr) + return false; + addr_t current_func_text_offset = 0; int current_sp_bytes_offset_from_fa = 0; bool is_aligned = false; @@ -1570,6 +1573,9 @@ bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( if (!m_register_map_initialized) return false; + if (m_disasm_context == nullptr) + return false; + while (offset < size) { int regno; int insn_len; diff --git a/contrib/llvm-project/lldb/source/Symbol/Block.cpp b/contrib/llvm-project/lldb/source/Symbol/Block.cpp index 6eeabe0ff5e4..f7d9c0d2d330 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Block.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Block.cpp @@ -314,6 +314,22 @@ bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) { return false; } +AddressRanges Block::GetRanges() { + AddressRanges ranges; + Function *function = CalculateSymbolContextFunction(); + if (!function) + return ranges; + for (size_t i = 0, e = m_ranges.GetSize(); i < e; ++i) { + ranges.emplace_back(); + auto &range = ranges.back(); + const Range &vm_range = m_ranges.GetEntryRef(i); + range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); + range.GetBaseAddress().Slide(vm_range.GetRangeBase()); + range.SetByteSize(vm_range.GetByteSize()); + } + return ranges; +} + bool Block::GetStartAddress(Address &addr) { if (m_ranges.IsEmpty()) return false; diff --git a/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp index 1b3cd23d9400..ddeacf18e855 100644 --- a/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/CompileUnit.cpp @@ -320,7 +320,7 @@ void CompileUnit::ResolveSymbolContext( src_location_spec.GetColumn() ? std::optional<uint16_t>(line_entry.column) : std::nullopt; - SourceLocationSpec found_entry(line_entry.file, line_entry.line, column, + SourceLocationSpec found_entry(line_entry.GetFile(), line_entry.line, column, inlines, exact); while (line_idx != UINT32_MAX) { diff --git a/contrib/llvm-project/lldb/source/Symbol/CompilerDecl.cpp b/contrib/llvm-project/lldb/source/Symbol/CompilerDecl.cpp index 0eb630e5b9e1..5fa0a32f041a 100644 --- a/contrib/llvm-project/lldb/source/Symbol/CompilerDecl.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/CompilerDecl.cpp @@ -9,6 +9,7 @@ #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Utility/Scalar.h" using namespace lldb_private; @@ -24,6 +25,10 @@ CompilerDeclContext CompilerDecl::GetDeclContext() const { return m_type_system->DeclGetDeclContext(m_opaque_decl); } +CompilerType CompilerDecl::GetType() const { + return m_type_system->GetTypeForDecl(m_opaque_decl); +} + CompilerType CompilerDecl::GetFunctionReturnType() const { return m_type_system->DeclGetFunctionReturnType(m_opaque_decl); } @@ -52,3 +57,7 @@ std::vector<lldb_private::CompilerContext> CompilerDecl::GetCompilerContext() const { return m_type_system->DeclGetCompilerContext(m_opaque_decl); } + +Scalar CompilerDecl::GetConstantValue() const { + return m_type_system->DeclGetConstantValue(m_opaque_decl); +} diff --git a/contrib/llvm-project/lldb/source/Symbol/CompilerType.cpp b/contrib/llvm-project/lldb/source/Symbol/CompilerType.cpp index 76b79daa6ac1..f8da9ef7b764 100644 --- a/contrib/llvm-project/lldb/source/Symbol/CompilerType.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/CompilerType.cpp @@ -108,6 +108,27 @@ bool CompilerType::IsConst() const { return false; } +unsigned CompilerType::GetPtrAuthKey() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthKey(m_type); + return 0; +} + +unsigned CompilerType::GetPtrAuthDiscriminator() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthDiscriminator(m_type); + return 0; +} + +bool CompilerType::GetPtrAuthAddressDiversity() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetPtrAuthAddressDiversity(m_type); + return false; +} + bool CompilerType::IsFunctionType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) @@ -664,6 +685,13 @@ CompilerType CompilerType::GetPointerType() const { return CompilerType(); } +CompilerType CompilerType::AddPtrAuthModifier(uint32_t payload) const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->AddPtrAuthModifier(m_type, payload); + return CompilerType(); +} + CompilerType CompilerType::GetLValueReferenceType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) @@ -770,13 +798,14 @@ lldb::Format CompilerType::GetFormat() const { return lldb::eFormatDefault; } -uint32_t CompilerType::GetNumChildren(bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) const { +llvm::Expected<uint32_t> +CompilerType::GetNumChildren(bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) return type_system_sp->GetNumChildren(m_type, omit_empty_base_classes, exe_ctx); - return 0; + return llvm::createStringError("invalid type"); } lldb::BasicType CompilerType::GetBasicTypeEnumeration() const { @@ -847,6 +876,12 @@ CompilerType::GetVirtualBaseClassAtIndex(size_t idx, return CompilerType(); } +CompilerDecl CompilerType::GetStaticFieldWithName(llvm::StringRef name) const { + if (IsValid()) + return GetTypeSystem()->GetStaticFieldWithName(m_type, name); + return CompilerDecl(); +} + uint32_t CompilerType::GetIndexOfFieldWithName( const char *name, CompilerType *field_compiler_type_ptr, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, @@ -866,7 +901,7 @@ uint32_t CompilerType::GetIndexOfFieldWithName( return UINT32_MAX; } -CompilerType CompilerType::GetChildCompilerTypeAtIndex( +llvm::Expected<CompilerType> CompilerType::GetChildCompilerTypeAtIndex( ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, uint32_t &child_byte_size, @@ -929,6 +964,15 @@ size_t CompilerType::GetIndexOfChildMemberWithName( return 0; } +CompilerType +CompilerType::GetDirectNestedTypeWithName(llvm::StringRef name) const { + if (IsValid() && !name.empty()) { + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->GetDirectNestedTypeWithName(m_type, name); + } + return CompilerType(); +} + size_t CompilerType::GetNumTemplateArguments(bool expand_pack) const { if (IsValid()) { if (auto type_system_sp = GetTypeSystem()) diff --git a/contrib/llvm-project/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/contrib/llvm-project/lldb/source/Symbol/DWARFCallFrameInfo.cpp index dc54d13ae23c..f3df8a2c27f5 100644 --- a/contrib/llvm-project/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -423,8 +423,7 @@ void DWARFCallFrameInfo::GetFDEIndex() { if (m_fde_index_initialized) // if two threads hit the locker return; - LLDB_SCOPED_TIMERF("%s - %s", LLVM_PRETTY_FUNCTION, - m_objfile.GetFileSpec().GetFilename().AsCString("")); + LLDB_SCOPED_TIMERF("%s", m_objfile.GetFileSpec().GetFilename().AsCString("")); bool clear_address_zeroth_bit = false; if (ArchSpec arch = m_objfile.GetArchitecture()) { diff --git a/contrib/llvm-project/lldb/source/Symbol/Function.cpp b/contrib/llvm-project/lldb/source/Symbol/Function.cpp index fdc090355771..96d8322b43d8 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Function.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Function.cpp @@ -220,17 +220,18 @@ Function *IndirectCallEdge::GetCallee(ModuleList &images, ExecutionContext &exe_ctx) { Log *log = GetLog(LLDBLog::Step); Status error; - Value callee_addr_val; - if (!call_target.Evaluate( - &exe_ctx, exe_ctx.GetRegisterContext(), LLDB_INVALID_ADDRESS, - /*initial_value_ptr=*/nullptr, - /*object_address_ptr=*/nullptr, callee_addr_val, &error)) { - LLDB_LOGF(log, "IndirectCallEdge: Could not evaluate expression: %s", - error.AsCString()); + llvm::Expected<Value> callee_addr_val = call_target.Evaluate( + &exe_ctx, exe_ctx.GetRegisterContext(), LLDB_INVALID_ADDRESS, + /*initial_value_ptr=*/nullptr, + /*object_address_ptr=*/nullptr); + if (!callee_addr_val) { + LLDB_LOG_ERROR(log, callee_addr_val.takeError(), + "IndirectCallEdge: Could not evaluate expression: {0}"); return nullptr; } - addr_t raw_addr = callee_addr_val.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + addr_t raw_addr = + callee_addr_val->GetScalar().ULongLong(LLDB_INVALID_ADDRESS); if (raw_addr == LLDB_INVALID_ADDRESS) { LLDB_LOG(log, "IndirectCallEdge: Could not extract address from scalar"); return nullptr; @@ -289,7 +290,7 @@ void Function::GetStartLineSourceInfo(FileSpec &source_file, if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), line_entry, nullptr)) { line_no = line_entry.line; - source_file = line_entry.file; + source_file = line_entry.GetFile(); } } } @@ -311,7 +312,7 @@ void Function::GetEndLineSourceInfo(FileSpec &source_file, uint32_t &line_no) { LineEntry line_entry; if (line_table->FindLineEntryByAddress(scratch_addr, line_entry, nullptr)) { line_no = line_entry.line; - source_file = line_entry.file; + source_file = line_entry.GetFile(); } } diff --git a/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp b/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp index 389f8dcb65d8..c941a6927cb9 100644 --- a/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/LineEntry.cpp @@ -14,12 +14,14 @@ using namespace lldb_private; LineEntry::LineEntry() - : range(), file(), is_start_of_statement(0), is_start_of_basic_block(0), - is_prologue_end(0), is_epilogue_begin(0), is_terminal_entry(0) {} + : range(), file_sp(std::make_shared<SupportFile>()), + original_file_sp(std::make_shared<SupportFile>()), + is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0), + is_epilogue_begin(0), is_terminal_entry(0) {} void LineEntry::Clear() { range.Clear(); - file.Clear(); + file_sp = std::make_shared<SupportFile>(); original_file_sp = std::make_shared<SupportFile>(); line = LLDB_INVALID_LINE_NUMBER; column = 0; @@ -35,6 +37,7 @@ bool LineEntry::IsValid() const { } bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const { + const FileSpec &file = file_sp->GetSpecOnly(); if (file) { if (show_fullpaths) file.Dump(s->AsRawOstream()); @@ -67,7 +70,7 @@ bool LineEntry::Dump(Stream *s, Target *target, bool show_file, return false; } if (show_file) - *s << ", file = " << file; + *s << ", file = " << GetFile(); if (line) s->Printf(", line = %u", line); if (column) @@ -103,7 +106,7 @@ bool LineEntry::GetDescription(Stream *s, lldb::DescriptionLevel level, Address::DumpStyleFileAddress); } - *s << ": " << file; + *s << ": " << GetFile(); if (line) { s->Printf(":%u", line); @@ -173,7 +176,7 @@ int LineEntry::Compare(const LineEntry &a, const LineEntry &b) { if (a.column > b.column) return +1; - return FileSpec::Compare(a.file, b.file, true); + return FileSpec::Compare(a.GetFile(), b.GetFile(), true); } AddressRange LineEntry::GetSameLineContiguousAddressRange( @@ -196,7 +199,8 @@ AddressRange LineEntry::GetSameLineContiguousAddressRange( next_line_sc.line_entry.range.GetByteSize() == 0) break; - if (*original_file_sp == *next_line_sc.line_entry.original_file_sp && + if (original_file_sp->Equal(*next_line_sc.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet) && (next_line_sc.line_entry.line == 0 || line == next_line_sc.line_entry.line)) { // Include any line 0 entries - they indicate that this is compiler- @@ -241,7 +245,9 @@ void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) { if (target_sp) { // Apply any file remappings to our file. if (auto new_file_spec = target_sp->GetSourcePathMap().FindFile( - original_file_sp->GetSpecOnly())) - file = *new_file_spec; + original_file_sp->GetSpecOnly())) { + file_sp = std::make_shared<SupportFile>(*new_file_spec, + original_file_sp->GetChecksum()); + } } } diff --git a/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp b/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp index 444135f63bc0..8fb002cc9317 100644 --- a/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/LineTable.cpp @@ -288,8 +288,8 @@ bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx, else line_entry.range.SetByteSize(0); - line_entry.file = - m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx); + line_entry.file_sp = std::make_shared<SupportFile>( + m_comp_unit->GetSupportFiles().GetFileSpecAtIndex(entry.file_idx)); line_entry.original_file_sp = m_comp_unit->GetSupportFiles().GetSupportFileAtIndex(entry.file_idx); line_entry.line = entry.line; @@ -360,7 +360,7 @@ void LineTable::Dump(Stream *s, Target *target, Address::DumpStyle style, SupportFileSP prev_file; for (size_t idx = 0; idx < count; ++idx) { ConvertEntryAtIndexToLineEntry(idx, line_entry); - line_entry.Dump(s, target, *prev_file != *line_entry.original_file_sp, + line_entry.Dump(s, target, !prev_file->Equal(*line_entry.original_file_sp), style, fallback_style, show_line_ranges); s->EOL(); prev_file = line_entry.original_file_sp; diff --git a/contrib/llvm-project/lldb/source/Symbol/ObjectFile.cpp b/contrib/llvm-project/lldb/source/Symbol/ObjectFile.cpp index d890ad92e831..2608a9c5fb79 100644 --- a/contrib/llvm-project/lldb/source/Symbol/ObjectFile.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/ObjectFile.cpp @@ -184,6 +184,15 @@ ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, return object_file_sp; } +bool ObjectFile::IsObjectFile(lldb_private::FileSpec file_spec) { + DataBufferSP data_sp; + offset_t data_offset = 0; + ModuleSP module_sp = std::make_shared<Module>(file_spec); + return static_cast<bool>(ObjectFile::FindPlugin( + module_sp, &file_spec, 0, FileSystem::Instance().GetByteSize(file_spec), + data_sp, data_offset)); +} + size_t ObjectFile::GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, diff --git a/contrib/llvm-project/lldb/source/Symbol/SaveCoreOptions.cpp b/contrib/llvm-project/lldb/source/Symbol/SaveCoreOptions.cpp new file mode 100644 index 000000000000..0f6fdac1ce22 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Symbol/SaveCoreOptions.cpp @@ -0,0 +1,53 @@ +//===-- SaveCoreOptions.cpp -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SaveCoreOptions.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; + +Status SaveCoreOptions::SetPluginName(const char *name) { + Status error; + if (!name || !name[0]) { + m_plugin_name = std::nullopt; + return error; + } + + if (!PluginManager::IsRegisteredObjectFilePluginName(name)) { + error.SetErrorStringWithFormat( + "plugin name '%s' is not a valid ObjectFile plugin name", name); + return error; + } + + m_plugin_name = name; + return error; +} + +void SaveCoreOptions::SetStyle(lldb::SaveCoreStyle style) { m_style = style; } + +void SaveCoreOptions::SetOutputFile(FileSpec file) { m_file = file; } + +std::optional<std::string> SaveCoreOptions::GetPluginName() const { + return m_plugin_name; +} + +lldb::SaveCoreStyle SaveCoreOptions::GetStyle() const { + return m_style.value_or(lldb::eSaveCoreUnspecified); +} + +const std::optional<lldb_private::FileSpec> +SaveCoreOptions::GetOutputFile() const { + return m_file; +} + +void SaveCoreOptions::Clear() { + m_file = std::nullopt; + m_plugin_name = std::nullopt; + m_style = std::nullopt; +} diff --git a/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp b/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp index 1895f299cc06..9b0042ffdb4b 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Symbol.cpp @@ -101,18 +101,15 @@ const Symbol &Symbol::operator=(const Symbol &rhs) { llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol, SectionList *section_list) { if (!section_list) - return llvm::make_error<llvm::StringError>("no section list provided", - llvm::inconvertibleErrorCode()); + return llvm::createStringError("no section list provided"); if (!symbol.value && !symbol.address) - return llvm::make_error<llvm::StringError>( - "symbol must contain either a value or an address", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "symbol must contain either a value or an address"); if (symbol.value && symbol.address) - return llvm::make_error<llvm::StringError>( - "symbol cannot contain both a value and an address", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "symbol cannot contain both a value and an address"); const uint64_t size = symbol.size.value_or(0); const bool is_artificial = false; @@ -133,9 +130,8 @@ llvm::Expected<Symbol> Symbol::FromJSON(const JSONSymbol &symbol, AddressRange(section_sp, offset, size), size_is_valid, contains_linker_annotations, flags); } - return llvm::make_error<llvm::StringError>( - llvm::formatv("no section found for address: {0:x}", *symbol.address), - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + llvm::formatv("no section found for address: {0:x}", *symbol.address)); } // Absolute symbols encode the integer value in the m_offset of the diff --git a/contrib/llvm-project/lldb/source/Symbol/SymbolContext.cpp b/contrib/llvm-project/lldb/source/Symbol/SymbolContext.cpp index 3c70b8d8743c..8f26e41d1920 100644 --- a/contrib/llvm-project/lldb/source/Symbol/SymbolContext.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/SymbolContext.cpp @@ -73,6 +73,7 @@ bool SymbolContext::DumpStopContext( Stream *s, ExecutionContextScope *exe_scope, const Address &addr, bool show_fullpaths, bool show_module, bool show_inlined_frames, bool show_function_arguments, bool show_function_name, + bool show_function_display_name, std::optional<Stream::HighlightSettings> settings) const { bool dumped_something = false; if (show_module && module_sp) { @@ -93,6 +94,8 @@ bool SymbolContext::DumpStopContext( ConstString name; if (!show_function_arguments) name = function->GetNameNoArguments(); + if (!name && show_function_display_name) + name = function->GetDisplayName(); if (!name) name = function->GetName(); if (name) @@ -146,7 +149,8 @@ bool SymbolContext::DumpStopContext( const bool show_function_name = true; return inline_parent_sc.DumpStopContext( s, exe_scope, inline_parent_addr, show_fullpaths, show_module, - show_inlined_frames, show_function_arguments, show_function_name); + show_inlined_frames, show_function_arguments, show_function_name, + show_function_display_name); } } else { if (line_entry.IsValid()) { @@ -164,7 +168,12 @@ bool SymbolContext::DumpStopContext( dumped_something = true; if (symbol->GetType() == eSymbolTypeTrampoline) s->PutCString("symbol stub for: "); - s->PutCStringColorHighlighted(symbol->GetName().GetStringRef(), settings); + ConstString name; + if (show_function_display_name) + name = symbol->GetDisplayName(); + if (!name) + name = symbol->GetName(); + s->PutCStringColorHighlighted(name.GetStringRef(), settings); } if (addr.IsValid() && symbol->ValueIsAddress()) { @@ -472,8 +481,8 @@ bool SymbolContext::GetParentOfInlinedScope(const Address &curr_frame_pc, curr_inlined_block->GetInlinedFunctionInfo(); next_frame_pc = range.GetBaseAddress(); next_frame_sc.line_entry.range.GetBaseAddress() = next_frame_pc; - next_frame_sc.line_entry.file = - curr_inlined_block_inlined_info->GetCallSite().GetFile(); + next_frame_sc.line_entry.file_sp = std::make_shared<SupportFile>( + curr_inlined_block_inlined_info->GetCallSite().GetFile()); next_frame_sc.line_entry.original_file_sp = std::make_shared<SupportFile>( curr_inlined_block_inlined_info->GetCallSite().GetFile()); diff --git a/contrib/llvm-project/lldb/source/Symbol/SymbolFile.cpp b/contrib/llvm-project/lldb/source/Symbol/SymbolFile.cpp index e318e2beb654..16ed98d7840f 100644 --- a/contrib/llvm-project/lldb/source/Symbol/SymbolFile.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/SymbolFile.cpp @@ -227,7 +227,7 @@ SymbolFileCommon::GetTypeSystemForLanguage(lldb::LanguageType language) { return type_system_or_err; } -uint64_t SymbolFileCommon::GetDebugInfoSize() { +uint64_t SymbolFileCommon::GetDebugInfoSize(bool load_all_debug_info) { if (!m_objfile_sp) return 0; ModuleSP module_sp(m_objfile_sp->GetModule()); diff --git a/contrib/llvm-project/lldb/source/Symbol/SymbolFileOnDemand.cpp b/contrib/llvm-project/lldb/source/Symbol/SymbolFileOnDemand.cpp index bdb1951d5125..0cfe9fc1514b 100644 --- a/contrib/llvm-project/lldb/source/Symbol/SymbolFileOnDemand.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/SymbolFileOnDemand.cpp @@ -457,9 +457,8 @@ SymbolFileOnDemand::GetTypeSystemForLanguage(LanguageType language) { Log *log = GetLog(); LLDB_LOG(log, "[{0}] {1} is skipped for language type {2}", GetSymbolFileName(), __FUNCTION__, language); - return llvm::make_error<llvm::StringError>( - "GetTypeSystemForLanguage is skipped by SymbolFileOnDemand", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "GetTypeSystemForLanguage is skipped by SymbolFileOnDemand"); } return m_sym_file_impl->GetTypeSystemForLanguage(language); } @@ -535,11 +534,11 @@ void SymbolFileOnDemand::PreloadSymbols() { return m_sym_file_impl->PreloadSymbols(); } -uint64_t SymbolFileOnDemand::GetDebugInfoSize() { +uint64_t SymbolFileOnDemand::GetDebugInfoSize(bool load_all_debug_info) { // Always return the real debug info size. LLDB_LOG(GetLog(), "[{0}] {1} is not skipped", GetSymbolFileName(), __FUNCTION__); - return m_sym_file_impl->GetDebugInfoSize(); + return m_sym_file_impl->GetDebugInfoSize(load_all_debug_info); } StatsDuration::Duration SymbolFileOnDemand::GetDebugInfoParseTime() { diff --git a/contrib/llvm-project/lldb/source/Symbol/SymbolLocator.cpp b/contrib/llvm-project/lldb/source/Symbol/SymbolLocator.cpp index 918f13ed9c19..93a5bc428b61 100644 --- a/contrib/llvm-project/lldb/source/Symbol/SymbolLocator.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/SymbolLocator.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/ThreadPool.h" @@ -18,12 +19,10 @@ using namespace lldb; using namespace lldb_private; void SymbolLocator::DownloadSymbolFileAsync(const UUID &uuid) { - if (!ModuleList::GetGlobalModuleListProperties().GetEnableBackgroundLookup()) - return; - static llvm::SmallSet<UUID, 8> g_seen_uuids; static std::mutex g_mutex; - Debugger::GetThreadPool().async([=]() { + + auto lookup = [=]() { { std::lock_guard<std::mutex> guard(g_mutex); if (g_seen_uuids.count(uuid)) @@ -36,12 +35,23 @@ void SymbolLocator::DownloadSymbolFileAsync(const UUID &uuid) { module_spec.GetUUID() = uuid; if (!PluginManager::DownloadObjectAndSymbolFile(module_spec, error, /*force_lookup=*/true, - /*copy_executable=*/false)) + /*copy_executable=*/true)) return; if (error.Fail()) return; Debugger::ReportSymbolChange(module_spec); - }); + }; + + switch (ModuleList::GetGlobalModuleListProperties().GetSymbolAutoDownload()) { + case eSymbolDownloadOff: + break; + case eSymbolDownloadBackground: + Debugger::GetThreadPool().async(lookup); + break; + case eSymbolDownloadForeground: + lookup(); + break; + }; } diff --git a/contrib/llvm-project/lldb/source/Symbol/Symtab.cpp b/contrib/llvm-project/lldb/source/Symbol/Symtab.cpp index 564a3a94cfa2..5b5bf5c3f6f8 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Symtab.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Symtab.cpp @@ -124,12 +124,8 @@ void Symtab::Dump(Stream *s, Target *target, SortOrder sort_order, DumpSymbolHeader(s); std::multimap<llvm::StringRef, const Symbol *> name_map; - for (const_iterator pos = m_symbols.begin(), end = m_symbols.end(); - pos != end; ++pos) { - const char *name = pos->GetName().AsCString(); - if (name && name[0]) - name_map.insert(std::make_pair(name, &(*pos))); - } + for (const Symbol &symbol : m_symbols) + name_map.emplace(symbol.GetName().GetStringRef(), &symbol); for (const auto &name_to_symbol : name_map) { const Symbol *symbol = name_to_symbol.second; @@ -138,6 +134,22 @@ void Symtab::Dump(Stream *s, Target *target, SortOrder sort_order, } } break; + case eSortOrderBySize: { + s->PutCString(" (sorted by size):\n"); + DumpSymbolHeader(s); + + std::multimap<size_t, const Symbol *, std::greater<size_t>> size_map; + for (const Symbol &symbol : m_symbols) + size_map.emplace(symbol.GetByteSize(), &symbol); + + size_t idx = 0; + for (const auto &size_to_symbol : size_map) { + const Symbol *symbol = size_to_symbol.second; + s->Indent(); + symbol->Dump(s, target, idx++, name_preference); + } + } break; + case eSortOrderByAddress: s->PutCString(" (sorted by address):\n"); DumpSymbolHeader(s); diff --git a/contrib/llvm-project/lldb/source/Symbol/Type.cpp b/contrib/llvm-project/lldb/source/Symbol/Type.cpp index 6069d066eaf6..e76574795733 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Type.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Type.cpp @@ -29,12 +29,20 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" +#include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; +llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &os, + const CompilerContext &rhs) { + StreamString lldb_stream; + rhs.Dump(lldb_stream); + return os << lldb_stream.GetString(); +} + bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain, llvm::ArrayRef<CompilerContext> pattern) { auto ctx = context_chain.begin(); @@ -67,45 +75,39 @@ bool lldb_private::contextMatches(llvm::ArrayRef<CompilerContext> context_chain, static CompilerContextKind ConvertTypeClass(lldb::TypeClass type_class) { if (type_class == eTypeClassAny) return CompilerContextKind::AnyType; - uint16_t result = 0; - if (type_class & lldb::eTypeClassClass) - result |= (uint16_t)CompilerContextKind::Class; - if (type_class & lldb::eTypeClassStruct) - result |= (uint16_t)CompilerContextKind::Struct; + CompilerContextKind result = {}; + if (type_class & (lldb::eTypeClassClass | lldb::eTypeClassStruct)) + result |= CompilerContextKind::ClassOrStruct; if (type_class & lldb::eTypeClassUnion) - result |= (uint16_t)CompilerContextKind::Union; + result |= CompilerContextKind::Union; if (type_class & lldb::eTypeClassEnumeration) - result |= (uint16_t)CompilerContextKind::Enum; + result |= CompilerContextKind::Enum; if (type_class & lldb::eTypeClassFunction) - result |= (uint16_t)CompilerContextKind::Function; + result |= CompilerContextKind::Function; if (type_class & lldb::eTypeClassTypedef) - result |= (uint16_t)CompilerContextKind::Typedef; - return (CompilerContextKind)result; + result |= CompilerContextKind::Typedef; + return result; } TypeQuery::TypeQuery(llvm::StringRef name, TypeQueryOptions options) : m_options(options) { - llvm::StringRef scope, basename; - lldb::TypeClass type_class = lldb::eTypeClassAny; - if (Type::GetTypeScopeAndBasename(name, scope, basename, type_class)) { - if (scope.consume_front("::")) - m_options |= e_exact_match; + if (std::optional<Type::ParsedName> parsed_name = + Type::GetTypeScopeAndBasename(name)) { + llvm::ArrayRef scope = parsed_name->scope; if (!scope.empty()) { - std::pair<llvm::StringRef, llvm::StringRef> scope_pair = - scope.split("::"); - while (!scope_pair.second.empty()) { - m_context.push_back({CompilerContextKind::AnyDeclContext, - ConstString(scope_pair.first.str())}); - scope_pair = scope_pair.second.split("::"); + if (scope[0] == "::") { + m_options |= e_exact_match; + scope = scope.drop_front(); + } + for (llvm::StringRef s : scope) { + m_context.push_back( + {CompilerContextKind::AnyDeclContext, ConstString(s)}); } - m_context.push_back({CompilerContextKind::AnyDeclContext, - ConstString(scope_pair.first.str())}); } - m_context.push_back( - {ConvertTypeClass(type_class), ConstString(basename.str())}); + m_context.push_back({ConvertTypeClass(parsed_name->type_class), + ConstString(parsed_name->basename)}); } else { - m_context.push_back( - {CompilerContextKind::AnyType, ConstString(name.str())}); + m_context.push_back({CompilerContextKind::AnyType, ConstString(name)}); } } @@ -203,11 +205,8 @@ void CompilerContext::Dump(Stream &s) const { case CompilerContextKind::Namespace: s << "Namespace"; break; - case CompilerContextKind::Class: - s << "Class"; - break; - case CompilerContextKind::Struct: - s << "Structure"; + case CompilerContextKind::ClassOrStruct: + s << "ClassOrStruct"; break; case CompilerContextKind::Union: s << "Union"; @@ -355,6 +354,9 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break; + case eEncodingIsLLVMPtrAuthUID: + s->PutCString(" (ptrauth type)"); + break; } } } @@ -416,6 +418,8 @@ void Type::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) { case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break; + case eEncodingIsLLVMPtrAuthUID: + s->PutCString(" (ptrauth type)"); } } @@ -477,7 +481,8 @@ std::optional<uint64_t> Type::GetByteSize(ExecutionContextScope *exe_scope) { // If we are a pointer or reference, then this is just a pointer size; case eEncodingIsPointerUID: case eEncodingIsLValueReferenceUID: - case eEncodingIsRValueReferenceUID: { + case eEncodingIsRValueReferenceUID: + case eEncodingIsLLVMPtrAuthUID: { if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { m_byte_size = arch.GetAddressByteSize(); m_byte_size_has_value = true; @@ -488,7 +493,7 @@ std::optional<uint64_t> Type::GetByteSize(ExecutionContextScope *exe_scope) { return {}; } -uint32_t Type::GetNumChildren(bool omit_empty_base_classes) { +llvm::Expected<uint32_t> Type::GetNumChildren(bool omit_empty_base_classes) { return GetForwardCompilerType().GetNumChildren(omit_empty_base_classes, nullptr); } @@ -621,6 +626,12 @@ bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { encoding_type->GetForwardCompilerType().GetRValueReferenceType(); break; + case eEncodingIsLLVMPtrAuthUID: + m_compiler_type = + encoding_type->GetForwardCompilerType().AddPtrAuthModifier( + m_payload); + break; + default: llvm_unreachable("Unhandled encoding_data_type."); } @@ -676,6 +687,10 @@ bool Type::ResolveCompilerType(ResolveState compiler_type_resolve_state) { m_compiler_type = void_compiler_type.GetRValueReferenceType(); break; + case eEncodingIsLLVMPtrAuthUID: + llvm_unreachable("Cannot handle eEncodingIsLLVMPtrAuthUID without " + "valid encoding_type"); + default: llvm_unreachable("Unhandled encoding_data_type."); } @@ -757,65 +772,56 @@ ConstString Type::GetQualifiedName() { return GetForwardCompilerType().GetTypeName(); } -bool Type::GetTypeScopeAndBasename(llvm::StringRef name, - llvm::StringRef &scope, - llvm::StringRef &basename, - TypeClass &type_class) { - type_class = eTypeClassAny; +std::optional<Type::ParsedName> +Type::GetTypeScopeAndBasename(llvm::StringRef name) { + ParsedName result; if (name.empty()) - return false; - - // Clear the scope in case we have just a type class and a basename. - scope = llvm::StringRef(); - basename = name; - if (basename.consume_front("struct ")) - type_class = eTypeClassStruct; - else if (basename.consume_front("class ")) - type_class = eTypeClassClass; - else if (basename.consume_front("union ")) - type_class = eTypeClassUnion; - else if (basename.consume_front("enum ")) - type_class = eTypeClassEnumeration; - else if (basename.consume_front("typedef ")) - type_class = eTypeClassTypedef; - - size_t namespace_separator = basename.find("::"); - if (namespace_separator == llvm::StringRef::npos) { - // If "name" started a type class we need to return true with no scope. - return type_class != eTypeClassAny; - } - - size_t template_begin = basename.find('<'); - while (namespace_separator != llvm::StringRef::npos) { - if (template_begin != llvm::StringRef::npos && - namespace_separator > template_begin) { - size_t template_depth = 1; - llvm::StringRef template_arg = - basename.drop_front(template_begin + 1); - while (template_depth > 0 && !template_arg.empty()) { - if (template_arg.front() == '<') - template_depth++; - else if (template_arg.front() == '>') - template_depth--; - template_arg = template_arg.drop_front(1); + return std::nullopt; + + if (name.consume_front("struct ")) + result.type_class = eTypeClassStruct; + else if (name.consume_front("class ")) + result.type_class = eTypeClassClass; + else if (name.consume_front("union ")) + result.type_class = eTypeClassUnion; + else if (name.consume_front("enum ")) + result.type_class = eTypeClassEnumeration; + else if (name.consume_front("typedef ")) + result.type_class = eTypeClassTypedef; + + if (name.consume_front("::")) + result.scope.push_back("::"); + + bool prev_is_colon = false; + size_t template_depth = 0; + size_t name_begin = 0; + for (const auto &pos : llvm::enumerate(name)) { + switch (pos.value()) { + case ':': + if (prev_is_colon && template_depth == 0) { + result.scope.push_back(name.slice(name_begin, pos.index() - 1)); + name_begin = pos.index() + 1; } - if (template_depth != 0) - return false; // We have an invalid type name. Bail out. - if (template_arg.empty()) - break; // The template ends at the end of the full name. - basename = template_arg; - } else { - basename = basename.drop_front(namespace_separator + 2); + break; + case '<': + ++template_depth; + break; + case '>': + if (template_depth == 0) + return std::nullopt; // Invalid name. + --template_depth; + break; } - template_begin = basename.find('<'); - namespace_separator = basename.find("::"); + prev_is_colon = pos.value() == ':'; } - if (basename.size() < name.size()) { - scope = name.take_front(name.size() - basename.size()); - return true; - } - return false; + + if (name_begin < name.size() && template_depth == 0) + result.basename = name.substr(name_begin); + else + return std::nullopt; + + return result; } ModuleSP Type::GetModule() { @@ -1176,21 +1182,8 @@ bool TypeImpl::GetDescription(lldb_private::Stream &strm, CompilerType TypeImpl::FindDirectNestedType(llvm::StringRef name) { if (name.empty()) return CompilerType(); - auto type_system = GetTypeSystem(/*prefer_dynamic*/ false); - auto *symbol_file = type_system->GetSymbolFile(); - if (!symbol_file) - return CompilerType(); - auto decl_context = type_system->GetCompilerDeclContextForType(m_static_type); - if (!decl_context.IsValid()) - return CompilerType(); - TypeQuery query(decl_context, ConstString(name), - TypeQueryOptions::e_find_one); - TypeResults results; - symbol_file->FindTypes(query, results); - TypeSP type_sp = results.GetFirstType(); - if (type_sp) - return type_sp->GetFullCompilerType(); - return CompilerType(); + return GetCompilerType(/*prefer_dynamic=*/false) + .GetDirectNestedTypeWithName(name); } bool TypeMemberFunctionImpl::IsValid() { diff --git a/contrib/llvm-project/lldb/source/Symbol/TypeList.cpp b/contrib/llvm-project/lldb/source/Symbol/TypeList.cpp index 2e101e0a8f57..574887189315 100644 --- a/contrib/llvm-project/lldb/source/Symbol/TypeList.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/TypeList.cpp @@ -96,112 +96,3 @@ void TypeList::Dump(Stream *s, bool show_context) { if (Type *t = pos->get()) t->Dump(s, show_context); } - -void TypeList::RemoveMismatchedTypes(llvm::StringRef qualified_typename, - bool exact_match) { - llvm::StringRef type_scope; - llvm::StringRef type_basename; - TypeClass type_class = eTypeClassAny; - if (!Type::GetTypeScopeAndBasename(qualified_typename, type_scope, - type_basename, type_class)) { - type_basename = qualified_typename; - type_scope = ""; - } - return RemoveMismatchedTypes(type_scope, type_basename, type_class, - exact_match); -} - -void TypeList::RemoveMismatchedTypes(llvm::StringRef type_scope, - llvm::StringRef type_basename, - TypeClass type_class, bool exact_match) { - // Our "collection" type currently is a std::map which doesn't have any good - // way to iterate and remove items from the map so we currently just make a - // new list and add all of the matching types to it, and then swap it into - // m_types at the end - collection matching_types; - - iterator pos, end = m_types.end(); - - for (pos = m_types.begin(); pos != end; ++pos) { - Type *the_type = pos->get(); - bool keep_match = false; - TypeClass match_type_class = eTypeClassAny; - - if (type_class != eTypeClassAny) { - match_type_class = the_type->GetForwardCompilerType().GetTypeClass(); - if ((match_type_class & type_class) == 0) - continue; - } - - ConstString match_type_name_const_str(the_type->GetQualifiedName()); - if (match_type_name_const_str) { - const char *match_type_name = match_type_name_const_str.GetCString(); - llvm::StringRef match_type_scope; - llvm::StringRef match_type_basename; - if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope, - match_type_basename, - match_type_class)) { - if (match_type_basename == type_basename) { - const size_t type_scope_size = type_scope.size(); - const size_t match_type_scope_size = match_type_scope.size(); - if (exact_match || (type_scope_size == match_type_scope_size)) { - keep_match = match_type_scope == type_scope; - } else { - if (match_type_scope_size > type_scope_size) { - const size_t type_scope_pos = match_type_scope.rfind(type_scope); - if (type_scope_pos == match_type_scope_size - type_scope_size) { - if (type_scope_pos >= 2) { - // Our match scope ends with the type scope we were looking - // for, but we need to make sure what comes before the - // matching type scope is a namespace boundary in case we are - // trying to match: type_basename = "d" type_scope = "b::c::" - // We want to match: - // match_type_scope "a::b::c::" - // But not: - // match_type_scope "a::bb::c::" - // So below we make sure what comes before "b::c::" in - // match_type_scope is "::", or the namespace boundary - if (match_type_scope[type_scope_pos - 1] == ':' && - match_type_scope[type_scope_pos - 2] == ':') { - keep_match = true; - } - } - } - } - } - } - } else { - // The type we are currently looking at doesn't exists in a namespace - // or class, so it only matches if there is no type scope... - keep_match = type_scope.empty() && type_basename == match_type_name; - } - } - - if (keep_match) { - matching_types.push_back(*pos); - } - } - m_types.swap(matching_types); -} - -void TypeList::RemoveMismatchedTypes(TypeClass type_class) { - if (type_class == eTypeClassAny) - return; - - // Our "collection" type currently is a std::map which doesn't have any good - // way to iterate and remove items from the map so we currently just make a - // new list and add all of the matching types to it, and then swap it into - // m_types at the end - collection matching_types; - - iterator pos, end = m_types.end(); - - for (pos = m_types.begin(); pos != end; ++pos) { - Type *the_type = pos->get(); - TypeClass match_type_class = - the_type->GetForwardCompilerType().GetTypeClass(); - if (match_type_class & type_class) - matching_types.push_back(*pos); - } - m_types.swap(matching_types); -} diff --git a/contrib/llvm-project/lldb/source/Symbol/TypeMap.cpp b/contrib/llvm-project/lldb/source/Symbol/TypeMap.cpp index 8933de53749c..9d7c05f318a1 100644 --- a/contrib/llvm-project/lldb/source/Symbol/TypeMap.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/TypeMap.cpp @@ -132,76 +132,3 @@ void TypeMap::Dump(Stream *s, bool show_context, for (const auto &pair : m_types) pair.second->Dump(s, show_context, level); } - -void TypeMap::RemoveMismatchedTypes(llvm::StringRef type_scope, - llvm::StringRef type_basename, - TypeClass type_class, bool exact_match) { - // Our "collection" type currently is a std::map which doesn't have any good - // way to iterate and remove items from the map so we currently just make a - // new list and add all of the matching types to it, and then swap it into - // m_types at the end - collection matching_types; - - iterator pos, end = m_types.end(); - - for (pos = m_types.begin(); pos != end; ++pos) { - Type *the_type = pos->second.get(); - bool keep_match = false; - TypeClass match_type_class = eTypeClassAny; - - if (type_class != eTypeClassAny) { - match_type_class = the_type->GetForwardCompilerType().GetTypeClass(); - if ((match_type_class & type_class) == 0) - continue; - } - - ConstString match_type_name_const_str(the_type->GetQualifiedName()); - if (match_type_name_const_str) { - const char *match_type_name = match_type_name_const_str.GetCString(); - llvm::StringRef match_type_scope; - llvm::StringRef match_type_basename; - if (Type::GetTypeScopeAndBasename(match_type_name, match_type_scope, - match_type_basename, - match_type_class)) { - if (match_type_basename == type_basename) { - const size_t type_scope_size = type_scope.size(); - const size_t match_type_scope_size = match_type_scope.size(); - if (exact_match || (type_scope_size == match_type_scope_size)) { - keep_match = match_type_scope == type_scope; - } else { - if (match_type_scope_size > type_scope_size) { - const size_t type_scope_pos = match_type_scope.rfind(type_scope); - if (type_scope_pos == match_type_scope_size - type_scope_size) { - if (type_scope_pos >= 2) { - // Our match scope ends with the type scope we were looking - // for, but we need to make sure what comes before the - // matching type scope is a namespace boundary in case we are - // trying to match: type_basename = "d" type_scope = "b::c::" - // We want to match: - // match_type_scope "a::b::c::" - // But not: - // match_type_scope "a::bb::c::" - // So below we make sure what comes before "b::c::" in - // match_type_scope is "::", or the namespace boundary - if (match_type_scope[type_scope_pos - 1] == ':' && - match_type_scope[type_scope_pos - 2] == ':') { - keep_match = true; - } - } - } - } - } - } - } else { - // The type we are currently looking at doesn't exists in a namespace - // or class, so it only matches if there is no type scope... - keep_match = type_scope.empty() && type_basename == match_type_name; - } - } - - if (keep_match) { - matching_types.insert(*pos); - } - } - m_types.swap(matching_types); -} diff --git a/contrib/llvm-project/lldb/source/Symbol/TypeSystem.cpp b/contrib/llvm-project/lldb/source/Symbol/TypeSystem.cpp index 59b1b39e635a..931ce1b0203a 100644 --- a/contrib/llvm-project/lldb/source/Symbol/TypeSystem.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/TypeSystem.cpp @@ -93,6 +93,11 @@ CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType TypeSystem::AddPtrAuthModifier(lldb::opaque_compiler_type_t type, + uint32_t payload) { + return CompilerType(); +} + CompilerType TypeSystem::AddVolatileModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); @@ -262,9 +267,8 @@ llvm::Expected<lldb::TypeSystemSP> TypeSystemMap::GetTypeSystemForLanguage( std::optional<CreateCallback> create_callback) { std::lock_guard<std::mutex> guard(m_mutex); if (m_clear_in_progress) - return llvm::make_error<llvm::StringError>( - "Unable to get TypeSystem because TypeSystemMap is being cleared", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "Unable to get TypeSystem because TypeSystemMap is being cleared"); collection::iterator pos = m_map.find(language); if (pos != m_map.end()) { @@ -272,11 +276,10 @@ llvm::Expected<lldb::TypeSystemSP> TypeSystemMap::GetTypeSystemForLanguage( assert(!pos->second->weak_from_this().expired()); return pos->second; } - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist"); } for (const auto &pair : m_map) { @@ -286,31 +289,27 @@ llvm::Expected<lldb::TypeSystemSP> TypeSystemMap::GetTypeSystemForLanguage( m_map[language] = pair.second; if (pair.second) return pair.second; - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist"); } } if (!create_callback) - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "Unable to find type system for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)), - llvm::inconvertibleErrorCode()); - + llvm::StringRef(Language::GetNameForLanguageType(language))); // Cache even if we get a shared pointer that contains a null type system // back. TypeSystemSP type_system_sp = (*create_callback)(); m_map[language] = type_system_sp; if (type_system_sp) return type_system_sp; - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist"); } llvm::Expected<lldb::TypeSystemSP> @@ -336,3 +335,14 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } return GetTypeSystemForLanguage(language); } + +bool TypeSystem::SupportsLanguageStatic(lldb::LanguageType language) { + if (language == eLanguageTypeUnknown || language >= eNumLanguageTypes) + return false; + + LanguageSet languages = + PluginManager::GetAllTypeSystemSupportedLanguagesForTypes(); + if (languages.Empty()) + return false; + return languages[language]; +} diff --git a/contrib/llvm-project/lldb/source/Symbol/UnwindTable.cpp b/contrib/llvm-project/lldb/source/Symbol/UnwindTable.cpp index 3c1a5187b110..11bedf3d6052 100644 --- a/contrib/llvm-project/lldb/source/Symbol/UnwindTable.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/UnwindTable.cpp @@ -84,6 +84,51 @@ void UnwindTable::Initialize() { } } +void UnwindTable::Update() { + if (!m_initialized) + return Initialize(); + + std::lock_guard<std::mutex> guard(m_mutex); + + ObjectFile *object_file = m_module.GetObjectFile(); + if (!object_file) + return; + + if (!m_object_file_unwind_up) + m_object_file_unwind_up = object_file->CreateCallFrameInfo(); + + SectionList *sl = m_module.GetSectionList(); + if (!sl) + return; + + SectionSP sect = sl->FindSectionByType(eSectionTypeEHFrame, true); + if (!m_eh_frame_up && sect) { + m_eh_frame_up = std::make_unique<DWARFCallFrameInfo>( + *object_file, sect, DWARFCallFrameInfo::EH); + } + + sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); + if (!m_debug_frame_up && sect) { + m_debug_frame_up = std::make_unique<DWARFCallFrameInfo>( + *object_file, sect, DWARFCallFrameInfo::DWARF); + } + + sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); + if (!m_compact_unwind_up && sect) { + m_compact_unwind_up = + std::make_unique<CompactUnwindInfo>(*object_file, sect); + } + + sect = sl->FindSectionByType(eSectionTypeARMexidx, true); + if (!m_arm_unwind_up && sect) { + SectionSP sect_extab = sl->FindSectionByType(eSectionTypeARMextab, true); + if (sect_extab.get()) { + m_arm_unwind_up = + std::make_unique<ArmUnwindInfo>(*object_file, sect, sect_extab); + } + } +} + UnwindTable::~UnwindTable() = default; std::optional<AddressRange> diff --git a/contrib/llvm-project/lldb/source/Symbol/Variable.cpp b/contrib/llvm-project/lldb/source/Symbol/Variable.cpp index 2bb2ff7db4b7..90edede0f065 100644 --- a/contrib/llvm-project/lldb/source/Symbol/Variable.cpp +++ b/contrib/llvm-project/lldb/source/Symbol/Variable.cpp @@ -27,6 +27,8 @@ #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" @@ -509,15 +511,17 @@ static void PrivateAutoCompleteMembers( CompilerType member_compiler_type = compiler_type.GetFieldAtIndex( i, member_name, nullptr, nullptr, nullptr); - if (partial_member_name.empty() || - llvm::StringRef(member_name).starts_with(partial_member_name)) { + if (partial_member_name.empty()) { + request.AddCompletion((prefix_path + member_name).str()); + } else if (llvm::StringRef(member_name) + .starts_with(partial_member_name)) { if (member_name == partial_member_name) { PrivateAutoComplete( frame, partial_path, prefix_path + member_name, // Anything that has been resolved // already will be in here member_compiler_type.GetCanonicalType(), request); - } else { + } else if (partial_path.empty()) { request.AddCompletion((prefix_path + member_name).str()); } } @@ -566,7 +570,9 @@ static void PrivateAutoComplete( case eTypeClassObjCObjectPointer: case eTypeClassPointer: { bool omit_empty_base_classes = true; - if (compiler_type.GetNumChildren(omit_empty_base_classes, nullptr) > 0) + if (llvm::expectedToStdOptional( + compiler_type.GetNumChildren(omit_empty_base_classes, nullptr)) + .value_or(0)) request.AddCompletion((prefix_path + "->").str()); else { request.AddCompletion(prefix_path.str()); diff --git a/contrib/llvm-project/lldb/source/Target/ABI.cpp b/contrib/llvm-project/lldb/source/Target/ABI.cpp index 86bf01180271..110b5c86fc42 100644 --- a/contrib/llvm-project/lldb/source/Target/ABI.cpp +++ b/contrib/llvm-project/lldb/source/Target/ABI.cpp @@ -147,6 +147,39 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, return return_valobj_sp; } +addr_t ABI::FixCodeAddress(lldb::addr_t pc) { + ProcessSP process_sp(GetProcessSP()); + + addr_t mask = process_sp->GetCodeAddressMask(); + if (mask == LLDB_INVALID_ADDRESS_MASK) + return pc; + + // Assume the high bit is used for addressing, which + // may not be correct on all architectures e.g. AArch64 + // where Top Byte Ignore mode is often used to store + // metadata in the top byte, and b55 is the bit used for + // differentiating between low- and high-memory addresses. + // That target's ABIs need to override this method. + bool is_highmem = pc & (1ULL << 63); + return is_highmem ? pc | mask : pc & (~mask); +} + +addr_t ABI::FixDataAddress(lldb::addr_t pc) { + ProcessSP process_sp(GetProcessSP()); + addr_t mask = process_sp->GetDataAddressMask(); + if (mask == LLDB_INVALID_ADDRESS_MASK) + return pc; + + // Assume the high bit is used for addressing, which + // may not be correct on all architectures e.g. AArch64 + // where Top Byte Ignore mode is often used to store + // metadata in the top byte, and b55 is the bit used for + // differentiating between low- and high-memory addresses. + // That target's ABIs need to override this method. + bool is_highmem = pc & (1ULL << 63); + return is_highmem ? pc | mask : pc & (~mask); +} + ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, bool persistent) const { ValueObjectSP return_valobj_sp; diff --git a/contrib/llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp b/contrib/llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp index 5f4682bd5c11..da7c102645c0 100644 --- a/contrib/llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/contrib/llvm-project/lldb/source/Target/AssertFrameRecognizer.cpp @@ -2,6 +2,7 @@ #include "lldb/Core/Module.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolLocation.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackFrameList.h" #include "lldb/Target/Target.h" @@ -13,18 +14,6 @@ using namespace lldb; using namespace lldb_private; namespace lldb_private { - -/// Stores a function module spec, symbol name and possibly an alternate symbol -/// name. -struct SymbolLocation { - FileSpec module_spec; - std::vector<ConstString> symbols; - - // The symbols are regular expressions. In such case all symbols are matched - // with their trailing @VER symbol version stripped. - bool symbols_are_regex = false; -}; - /// Fetches the abort frame location depending on the current platform. /// /// \param[in] os diff --git a/contrib/llvm-project/lldb/source/Target/InstrumentationRuntime.cpp b/contrib/llvm-project/lldb/source/Target/InstrumentationRuntime.cpp index 9f22a1be20cc..9da06e8e155a 100644 --- a/contrib/llvm-project/lldb/source/Target/InstrumentationRuntime.cpp +++ b/contrib/llvm-project/lldb/source/Target/InstrumentationRuntime.cpp @@ -60,6 +60,8 @@ void InstrumentationRuntime::ModulesDidLoad( if (CheckIfRuntimeIsValid(module_sp)) { SetRuntimeModuleSP(module_sp); Activate(); + if (!IsActive()) + SetRuntimeModuleSP({}); // Don't cache module if activation failed. return false; // Stop iterating, we're done. } } diff --git a/contrib/llvm-project/lldb/source/Target/Language.cpp b/contrib/llvm-project/lldb/source/Target/Language.cpp index caf3e6636c1d..d0bffe441f63 100644 --- a/contrib/llvm-project/lldb/source/Target/Language.cpp +++ b/contrib/llvm-project/lldb/source/Target/Language.cpp @@ -13,11 +13,13 @@ #include "lldb/Target/Language.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeList.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Stream.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Threading.h" using namespace lldb; @@ -27,6 +29,35 @@ using namespace lldb_private::formatters; typedef std::unique_ptr<Language> LanguageUP; typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap; +#define LLDB_PROPERTIES_language +#include "TargetProperties.inc" + +enum { +#define LLDB_PROPERTIES_language +#include "TargetPropertiesEnum.inc" +}; + +LanguageProperties &Language::GetGlobalLanguageProperties() { + static LanguageProperties g_settings; + return g_settings; +} + +llvm::StringRef LanguageProperties::GetSettingName() { + static constexpr llvm::StringLiteral g_setting_name("language"); + return g_setting_name; +} + +LanguageProperties::LanguageProperties() { + m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); + m_collection_sp->Initialize(g_language_properties); +} + +bool LanguageProperties::GetEnableFilterForLineBreakpoints() const { + const uint32_t idx = ePropertyEnableFilterForLineBreakpoints; + return GetPropertyAtIndexAs<bool>( + idx, g_language_properties[idx].default_uint_value != 0); +} + static LanguagesMap &GetLanguagesMap() { static LanguagesMap *g_map = nullptr; static llvm::once_flag g_initialize; @@ -502,3 +533,36 @@ Language::Language() = default; // Destructor Language::~Language() = default; + +SourceLanguage::SourceLanguage(lldb::LanguageType language_type) { + auto lname = + llvm::dwarf::toDW_LNAME((llvm::dwarf::SourceLanguage)language_type); + if (!lname) + return; + name = lname->first; + version = lname->second; +} + +lldb::LanguageType SourceLanguage::AsLanguageType() const { + if (auto lang = llvm::dwarf::toDW_LANG((llvm::dwarf::SourceLanguageName)name, + version)) + return (lldb::LanguageType)*lang; + return lldb::eLanguageTypeUnknown; +} + +llvm::StringRef SourceLanguage::GetDescription() const { + LanguageType type = AsLanguageType(); + if (type) + return Language::GetNameForLanguageType(type); + return llvm::dwarf::LanguageDescription( + (llvm::dwarf::SourceLanguageName)name); +} +bool SourceLanguage::IsC() const { return name == llvm::dwarf::DW_LNAME_C; } + +bool SourceLanguage::IsObjC() const { + return name == llvm::dwarf::DW_LNAME_ObjC; +} + +bool SourceLanguage::IsCPlusPlus() const { + return name == llvm::dwarf::DW_LNAME_C_plus_plus; +} diff --git a/contrib/llvm-project/lldb/source/Target/PathMappingList.cpp b/contrib/llvm-project/lldb/source/Target/PathMappingList.cpp index c369018122a5..9c283b0146fe 100644 --- a/contrib/llvm-project/lldb/source/Target/PathMappingList.cpp +++ b/contrib/llvm-project/lldb/source/Target/PathMappingList.cpp @@ -86,8 +86,8 @@ bool PathMappingList::AppendUnique(llvm::StringRef path, auto normalized_replacement = NormalizePath(replacement); std::lock_guard<std::recursive_mutex> lock(m_mutex); for (const auto &pair : m_pairs) { - if (pair.first.GetStringRef().equals(normalized_path) && - pair.second.GetStringRef().equals(normalized_replacement)) + if (pair.first.GetStringRef() == normalized_path && + pair.second.GetStringRef() == normalized_replacement) return false; } Append(path, replacement, notify); diff --git a/contrib/llvm-project/lldb/source/Target/Platform.cpp b/contrib/llvm-project/lldb/source/Target/Platform.cpp index 4ce290dfbe03..ab80fe4c8ba2 100644 --- a/contrib/llvm-project/lldb/source/Target/Platform.cpp +++ b/contrib/llvm-project/lldb/source/Target/Platform.cpp @@ -161,40 +161,6 @@ Platform::LocateExecutableScriptingResources(Target *target, Module &module, return FileSpecList(); } -// PlatformSP -// Platform::FindPlugin (Process *process, ConstString plugin_name) -//{ -// PlatformCreateInstance create_callback = nullptr; -// if (plugin_name) -// { -// create_callback = -// PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); -// if (create_callback) -// { -// ArchSpec arch; -// if (process) -// { -// arch = process->GetTarget().GetArchitecture(); -// } -// PlatformSP platform_sp(create_callback(process, &arch)); -// if (platform_sp) -// return platform_sp; -// } -// } -// else -// { -// for (uint32_t idx = 0; (create_callback = -// PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != nullptr; -// ++idx) -// { -// PlatformSP platform_sp(create_callback(process, nullptr)); -// if (platform_sp) -// return platform_sp; -// } -// } -// return PlatformSP(); -//} - Status Platform::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, @@ -766,42 +732,6 @@ Status Platform::ResolveExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { - Status error; - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - if (module_spec.GetArchitecture().IsValid()) { - error = ModuleList::GetSharedModule(module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, - nullptr); - } else { - // No valid architecture was specified, ask the platform for the - // architectures that we should be using (in the correct order) and see - // if we can find a match that way - ModuleSpec arch_module_spec(module_spec); - ArchSpec process_host_arch; - for (const ArchSpec &arch : - GetSupportedArchitectures(process_host_arch)) { - arch_module_spec.GetArchitecture() = arch; - error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, - nullptr); - // Did we find an executable using one of the - if (error.Success() && exe_module_sp) - break; - } - } - } else { - error.SetErrorStringWithFormat( - "'%s' does not exist", module_spec.GetFileSpec().GetPath().c_str()); - } - return error; -} - -Status -Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec, - lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr) { - Status error; // We may connect to a process and use the provided executable (Don't use // local $PATH). @@ -810,57 +740,57 @@ Platform::ResolveRemoteExecutable(const ModuleSpec &module_spec, // Resolve any executable within a bundle on MacOSX Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) || - module_spec.GetUUID().IsValid()) { - if (resolved_module_spec.GetArchitecture().IsValid() || - resolved_module_spec.GetUUID().IsValid()) { - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, - nullptr); + if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec()) && + !module_spec.GetUUID().IsValid()) + return Status::createWithFormat("'{0}' does not exist", + resolved_module_spec.GetFileSpec()); + + if (resolved_module_spec.GetArchitecture().IsValid() || + resolved_module_spec.GetUUID().IsValid()) { + Status error = + ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, nullptr); + if (exe_module_sp && exe_module_sp->GetObjectFile()) + return error; + exe_module_sp.reset(); + } + // No valid architecture was specified or the exact arch wasn't found. + // Ask the platform for the architectures that we should be using (in the + // correct order) and see if we can find a match that way. + StreamString arch_names; + llvm::ListSeparator LS; + ArchSpec process_host_arch; + Status error; + for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { + resolved_module_spec.GetArchitecture() = arch; + error = + ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, nullptr); + if (error.Success()) { if (exe_module_sp && exe_module_sp->GetObjectFile()) - return error; - exe_module_sp.reset(); + break; + error.SetErrorToGenericError(); } - // No valid architecture was specified or the exact arch wasn't found so - // ask the platform for the architectures that we should be using (in the - // correct order) and see if we can find a match that way - StreamString arch_names; - llvm::ListSeparator LS; - ArchSpec process_host_arch; - for (const ArchSpec &arch : GetSupportedArchitectures(process_host_arch)) { - resolved_module_spec.GetArchitecture() = arch; - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, - nullptr); - // Did we find an executable using one of the - if (error.Success()) { - if (exe_module_sp && exe_module_sp->GetObjectFile()) - break; - else - error.SetErrorToGenericError(); - } - arch_names << LS << arch.GetArchitectureName(); - } + arch_names << LS << arch.GetArchitectureName(); + } - if (error.Fail() || !exe_module_sp) { - if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) { - error.SetErrorStringWithFormatv( - "'{0}' doesn't contain any '{1}' platform architectures: {2}", - resolved_module_spec.GetFileSpec(), GetPluginName(), - arch_names.GetData()); - } else { - error.SetErrorStringWithFormatv("'{0}' is not readable", - resolved_module_spec.GetFileSpec()); - } - } - } else { - error.SetErrorStringWithFormatv("'{0}' does not exist", + if (exe_module_sp && error.Success()) + return {}; + + if (!FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) + return Status::createWithFormat("'{0}' is not readable", resolved_module_spec.GetFileSpec()); - } - return error; + if (!ObjectFile::IsObjectFile(resolved_module_spec.GetFileSpec())) + return Status::createWithFormat("'{0}' is not a valid executable", + resolved_module_spec.GetFileSpec()); + + return Status::createWithFormat( + "'{0}' doesn't contain any '{1}' platform architectures: {2}", + resolved_module_spec.GetFileSpec(), GetPluginName(), + arch_names.GetData()); } Status Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, @@ -1197,9 +1127,35 @@ Status Platform::PutFile(const FileSpec &source, const FileSpec &destination, if (!source_file) return Status(source_file.takeError()); Status error; + + bool requires_upload = true; + llvm::ErrorOr<llvm::MD5::MD5Result> remote_md5 = CalculateMD5(destination); + if (std::error_code ec = remote_md5.getError()) { + LLDB_LOG(log, "[PutFile] couldn't get md5 sum of destination: {0}", + ec.message()); + } else { + llvm::ErrorOr<llvm::MD5::MD5Result> local_md5 = + llvm::sys::fs::md5_contents(source.GetPath()); + if (std::error_code ec = local_md5.getError()) { + LLDB_LOG(log, "[PutFile] couldn't get md5 sum of source: {0}", + ec.message()); + } else { + LLDB_LOGF(log, "[PutFile] destination md5: %016" PRIx64 "%016" PRIx64, + remote_md5->high(), remote_md5->low()); + LLDB_LOGF(log, "[PutFile] local md5: %016" PRIx64 "%016" PRIx64, + local_md5->high(), local_md5->low()); + requires_upload = *remote_md5 != *local_md5; + } + } + + if (!requires_upload) { + LLDB_LOGF(log, "[PutFile] skipping PutFile because md5sums match"); + return error; + } + uint32_t permissions = source_file.get()->GetPermissions(error); if (permissions == 0) - permissions = lldb::eFilePermissionsFileDefault; + permissions = lldb::eFilePermissionsUserRWX; lldb::user_id_t dest_file = OpenFile( destination, File::eOpenOptionCanCreate | File::eOpenOptionWriteOnly | @@ -1313,15 +1269,11 @@ lldb_private::Status Platform::RunShellCommand( return Status("unable to run a remote command without a platform"); } -bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, - uint64_t &high) { +llvm::ErrorOr<llvm::MD5::MD5Result> +Platform::CalculateMD5(const FileSpec &file_spec) { if (!IsHost()) - return false; - auto Result = llvm::sys::fs::md5_contents(file_spec.GetPath()); - if (!Result) - return false; - std::tie(high, low) = Result->words(); - return true; + return std::make_error_code(std::errc::not_supported); + return llvm::sys::fs::md5_contents(file_spec.GetPath()); } void Platform::SetLocalCacheDirectory(const char *local) { @@ -1494,8 +1446,8 @@ Platform::GetCachedExecutable(ModuleSpec &module_spec, Status error = GetRemoteSharedModule( module_spec, nullptr, module_sp, [&](const ModuleSpec &spec) { - return ResolveRemoteExecutable(spec, module_sp, - module_search_paths_ptr); + return Platform::ResolveExecutable(spec, module_sp, + module_search_paths_ptr); }, nullptr); if (error.Success()) { diff --git a/contrib/llvm-project/lldb/source/Target/Process.cpp b/contrib/llvm-project/lldb/source/Target/Process.cpp index e1c16ca21643..d5a639d9beac 100644 --- a/contrib/llvm-project/lldb/source/Target/Process.cpp +++ b/contrib/llvm-project/lldb/source/Target/Process.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/DynamicCheckerFunctions.h" #include "lldb/Expression/UserExpression.h" @@ -63,6 +64,8 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Target/VerboseTrapFrameRecognizer.h" +#include "lldb/Utility/AddressableBits.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" @@ -111,6 +114,33 @@ public: } }; +class ProcessMemoryIterator { +public: + ProcessMemoryIterator(Process &process, lldb::addr_t base) + : m_process(process), m_base_addr(base) {} + + bool IsValid() { return m_is_valid; } + + uint8_t operator[](lldb::addr_t offset) { + if (!IsValid()) + return 0; + + uint8_t retval = 0; + Status error; + if (0 == m_process.ReadMemory(m_base_addr + offset, &retval, 1, error)) { + m_is_valid = false; + return 0; + } + + return retval; + } + +private: + Process &m_process; + const lldb::addr_t m_base_addr; + bool m_is_valid = true; +}; + static constexpr OptionEnumValueElement g_follow_fork_mode_values[] = { { eFollowParent, @@ -407,8 +437,8 @@ ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, return process_sp; } -ConstString &Process::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.process"); +llvm::StringRef Process::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.process"); return class_name; } @@ -422,7 +452,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, const UnixSignalsSP &unix_signals_sp) : ProcessProperties(this), Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()), - Process::GetStaticBroadcasterClass().AsCString()), + Process::GetStaticBroadcasterClass().str()), m_target_wp(target_sp), m_public_state(eStateUnloaded), m_private_state(eStateUnloaded), m_private_state_broadcaster(nullptr, @@ -432,12 +462,10 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_private_state_listener_sp( Listener::MakeListener("lldb.process.internal_state_listener")), m_mod_id(), m_process_unique_id(0), m_thread_index_id(0), - m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(), - m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this), - m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this), - m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), - m_watchpoint_resource_list(), m_notifications(), m_image_tokens(), - m_breakpoint_site_list(), m_dynamic_checkers_up(), + m_thread_id_to_index_id_map(), m_exit_status(-1), + m_thread_list_real(*this), m_thread_list(*this), m_thread_plans(*this), + m_extended_thread_list(*this), m_extended_thread_stop_id(0), + m_queue_list(this), m_queue_list_stop_id(0), m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(), m_stdio_communication("process.stdio"), m_stdio_communication_mutex(), m_stdin_forward(false), m_stdout_data(), m_stderr_data(), @@ -496,7 +524,11 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, if (!value_sp->OptionWasSet() && platform_cache_line_size != 0) value_sp->SetValueAs(platform_cache_line_size); + // FIXME: Frame recognizer registration should not be done in Target. + // We should have a plugin do the registration instead, for example, a + // common C LanguageRuntime plugin. RegisterAssertFrameRecognizer(this); + RegisterVerboseTrapFrameRecognizer(*this); } Process::~Process() { @@ -1155,8 +1187,8 @@ void Process::UpdateThreadListIfNeeded() { // mutex between the call to UpdateThreadList(...) and the // os->UpdateThreadList(...) so it doesn't change on us ThreadList &old_thread_list = m_thread_list; - ThreadList real_thread_list(this); - ThreadList new_thread_list(this); + ThreadList real_thread_list(*this); + ThreadList new_thread_list(*this); // Always update the thread list with the protocol specific thread list, // but only update if "true" is returned if (UpdateThreadList(m_thread_list_real, real_thread_list)) { @@ -1979,6 +2011,129 @@ size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) { } } +void Process::DoFindInMemory(lldb::addr_t start_addr, lldb::addr_t end_addr, + const uint8_t *buf, size_t size, + AddressRanges &matches, size_t alignment, + size_t max_matches) { + // Inputs are already validated in FindInMemory() functions. + assert(buf != nullptr); + assert(size > 0); + assert(alignment > 0); + assert(max_matches > 0); + assert(start_addr != LLDB_INVALID_ADDRESS); + assert(end_addr != LLDB_INVALID_ADDRESS); + assert(start_addr < end_addr); + + lldb::addr_t start = llvm::alignTo(start_addr, alignment); + while (matches.size() < max_matches && (start + size) < end_addr) { + const lldb::addr_t found_addr = FindInMemory(start, end_addr, buf, size); + if (found_addr == LLDB_INVALID_ADDRESS) + break; + + if (found_addr % alignment) { + // We need to check the alignment because the FindInMemory uses a special + // algorithm to efficiently search mememory but doesn't support alignment. + start = llvm::alignTo(start + 1, alignment); + continue; + } + + matches.emplace_back(found_addr, size); + start = found_addr + alignment; + } +} + +AddressRanges Process::FindRangesInMemory(const uint8_t *buf, uint64_t size, + const AddressRanges &ranges, + size_t alignment, size_t max_matches, + Status &error) { + AddressRanges matches; + if (buf == nullptr) { + error.SetErrorString("buffer is null"); + return matches; + } + if (size == 0) { + error.SetErrorString("buffer size is zero"); + return matches; + } + if (ranges.empty()) { + error.SetErrorString("empty ranges"); + return matches; + } + if (alignment == 0) { + error.SetErrorString("alignment must be greater than zero"); + return matches; + } + if (max_matches == 0) { + error.SetErrorString("max_matches must be greater than zero"); + return matches; + } + + int resolved_ranges = 0; + Target &target = GetTarget(); + for (size_t i = 0; i < ranges.size(); ++i) { + if (matches.size() >= max_matches) + break; + const AddressRange &range = ranges[i]; + if (range.IsValid() == false) + continue; + + const lldb::addr_t start_addr = + range.GetBaseAddress().GetLoadAddress(&target); + if (start_addr == LLDB_INVALID_ADDRESS) + continue; + + ++resolved_ranges; + const lldb::addr_t end_addr = start_addr + range.GetByteSize(); + DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, + max_matches); + } + + if (resolved_ranges > 0) + error.Clear(); + else + error.SetErrorString("unable to resolve any ranges"); + + return matches; +} + +lldb::addr_t Process::FindInMemory(const uint8_t *buf, uint64_t size, + const AddressRange &range, size_t alignment, + Status &error) { + if (buf == nullptr) { + error.SetErrorString("buffer is null"); + return LLDB_INVALID_ADDRESS; + } + if (size == 0) { + error.SetErrorString("buffer size is zero"); + return LLDB_INVALID_ADDRESS; + } + if (!range.IsValid()) { + error.SetErrorString("range is invalid"); + return LLDB_INVALID_ADDRESS; + } + if (alignment == 0) { + error.SetErrorString("alignment must be greater than zero"); + return LLDB_INVALID_ADDRESS; + } + + Target &target = GetTarget(); + const lldb::addr_t start_addr = + range.GetBaseAddress().GetLoadAddress(&target); + if (start_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorString("range load address is invalid"); + return LLDB_INVALID_ADDRESS; + } + const lldb::addr_t end_addr = start_addr + range.GetByteSize(); + + AddressRanges matches; + DoFindInMemory(start_addr, end_addr, buf, size, matches, alignment, 1); + if (matches.empty()) + return LLDB_INVALID_ADDRESS; + + error.Clear(); + return matches[0].GetBaseAddress().GetLoadAddress(&target); +} + size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str, Status &error) { char buf[256]; @@ -2396,6 +2551,14 @@ ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec, ModuleSP module_sp(new Module(file_spec, ArchSpec())); if (module_sp) { Status error; + std::unique_ptr<Progress> progress_up; + // Reading an ObjectFile from a local corefile is very fast, + // only print a progress update if we're reading from a + // live session which might go over gdb remote serial protocol. + if (IsLiveDebugSession()) + progress_up = std::make_unique<Progress>( + "Reading binary from memory", file_spec.GetFilename().GetString()); + ObjectFile *objfile = module_sp->GetMemoryObjectFile( shared_from_this(), header_addr, error, size_to_read); if (objfile) @@ -2937,14 +3100,11 @@ void Process::CompleteAttach() { DidAttach(process_arch); if (process_arch.IsValid()) { + LLDB_LOG(log, + "Process::{0} replacing process architecture with DidAttach() " + "architecture: \"{1}\"", + __FUNCTION__, process_arch.GetTriple().getTriple()); GetTarget().SetArchitecture(process_arch); - if (log) { - const char *triple_str = process_arch.GetTriple().getTriple().c_str(); - LLDB_LOGF(log, - "Process::%s replacing process architecture with DidAttach() " - "architecture: %s", - __FUNCTION__, triple_str ? triple_str : "<null>"); - } } // We just attached. If we have a platform, ask it for the process @@ -3193,6 +3353,33 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) { return Status(); } +lldb::addr_t Process::FindInMemory(lldb::addr_t low, lldb::addr_t high, + const uint8_t *buf, size_t size) { + const size_t region_size = high - low; + + if (region_size < size) + return LLDB_INVALID_ADDRESS; + + std::vector<size_t> bad_char_heuristic(256, size); + ProcessMemoryIterator iterator(*this, low); + + for (size_t idx = 0; idx < size - 1; idx++) { + decltype(bad_char_heuristic)::size_type bcu_idx = buf[idx]; + bad_char_heuristic[bcu_idx] = size - idx - 1; + } + for (size_t s = 0; s <= (region_size - size);) { + int64_t j = size - 1; + while (j >= 0 && buf[j] == iterator[s + j]) + j--; + if (j < 0) + return low + s; + else + s += bad_char_heuristic[iterator[s + size - 1]]; + } + + return LLDB_INVALID_ADDRESS; +} + Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) { Status error; @@ -3859,8 +4046,8 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { // case we should tell it to stop doing that. Normally, we don't NEED // to do that because we will next close the communication to the stub // and that will get it to shut down. But there are remote debugging - // cases where relying on that side-effect causes the shutdown to be - // flakey, so we should send a positive signal to interrupt the wait. + // cases where relying on that side-effect causes the shutdown to be + // flakey, so we should send a positive signal to interrupt the wait. Status error = HaltPrivate(); BroadcastEvent(eBroadcastBitInterrupt, nullptr); } else if (StateIsRunningState(m_last_broadcast_state)) { @@ -3977,7 +4164,6 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, ThreadList &curr_thread_list = process_sp->GetThreadList(); uint32_t num_threads = curr_thread_list.GetSize(); - uint32_t idx; // The actions might change one of the thread's stop_info's opinions about // whether we should stop the process, so we need to query that as we go. @@ -3987,23 +4173,18 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, // get that wrong (which is possible) then the thread list might have // changed, and that would cause our iteration here to crash. We could // make a copy of the thread list, but we'd really like to also know if it - // has changed at all, so we make up a vector of the thread ID's and check - // what we get back against this list & bag out if anything differs. - ThreadList not_suspended_thread_list(process_sp.get()); - std::vector<uint32_t> thread_index_array(num_threads); - uint32_t not_suspended_idx = 0; - for (idx = 0; idx < num_threads; ++idx) { + // has changed at all, so we store the original thread ID's of all threads and + // check what we get back against this list & bag out if anything differs. + std::vector<std::pair<ThreadSP, size_t>> not_suspended_threads; + for (uint32_t idx = 0; idx < num_threads; ++idx) { lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx); /* Filter out all suspended threads, they could not be the reason of stop and no need to perform any actions on them. */ - if (thread_sp->GetResumeState() != eStateSuspended) { - not_suspended_thread_list.AddThread(thread_sp); - thread_index_array[not_suspended_idx] = thread_sp->GetIndexID(); - not_suspended_idx++; - } + if (thread_sp->GetResumeState() != eStateSuspended) + not_suspended_threads.emplace_back(thread_sp, thread_sp->GetIndexID()); } // Use this to track whether we should continue from here. We will only @@ -4019,8 +4200,7 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, // is, and it's better to let the user decide than continue behind their // backs. - for (idx = 0; idx < not_suspended_thread_list.GetSize(); ++idx) { - curr_thread_list = process_sp->GetThreadList(); + for (auto [thread_sp, thread_index] : not_suspended_threads) { if (curr_thread_list.GetSize() != num_threads) { Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); LLDB_LOGF( @@ -4030,14 +4210,11 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, break; } - lldb::ThreadSP thread_sp = not_suspended_thread_list.GetThreadAtIndex(idx); - - if (thread_sp->GetIndexID() != thread_index_array[idx]) { + if (thread_sp->GetIndexID() != thread_index) { Log *log(GetLog(LLDBLog::Step | LLDBLog::Process)); - LLDB_LOGF(log, - "The thread at position %u changed from %u to %u while " - "processing event.", - idx, thread_index_array[idx], thread_sp->GetIndexID()); + LLDB_LOG(log, + "The thread {0} changed from {1} to {2} while processing event.", + thread_sp.get(), thread_index, thread_sp->GetIndexID()); break; } @@ -4073,7 +4250,22 @@ bool Process::ProcessEventData::ShouldStop(Event *event_ptr, return still_should_stop; } +bool Process::ProcessEventData::ForwardEventToPendingListeners( + Event *event_ptr) { + // STDIO and the other async event notifications should always be forwarded. + if (event_ptr->GetType() != Process::eBroadcastBitStateChanged) + return true; + + // For state changed events, if the update state is zero, we are handling + // this on the private state thread. We should wait for the public event. + return m_update_state == 1; +} + void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) { + // We only have work to do for state changed events: + if (event_ptr->GetType() != Process::eBroadcastBitStateChanged) + return; + ProcessSP process_sp(m_process_wp.lock()); if (!process_sp) @@ -4281,25 +4473,31 @@ void Process::CalculateExecutionContext(ExecutionContext &exe_ctx) { // return Host::GetArchSpecForExistingProcess (process_name); //} +EventSP Process::CreateEventFromProcessState(uint32_t event_type) { + auto event_data_sp = + std::make_shared<ProcessEventData>(shared_from_this(), GetState()); + return std::make_shared<Event>(event_type, event_data_sp); +} + void Process::AppendSTDOUT(const char *s, size_t len) { std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); m_stdout_data.append(s, len); - BroadcastEventIfUnique(eBroadcastBitSTDOUT, - new ProcessEventData(shared_from_this(), GetState())); + auto event_sp = CreateEventFromProcessState(eBroadcastBitSTDOUT); + BroadcastEventIfUnique(event_sp); } void Process::AppendSTDERR(const char *s, size_t len) { std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); m_stderr_data.append(s, len); - BroadcastEventIfUnique(eBroadcastBitSTDERR, - new ProcessEventData(shared_from_this(), GetState())); + auto event_sp = CreateEventFromProcessState(eBroadcastBitSTDERR); + BroadcastEventIfUnique(event_sp); } void Process::BroadcastAsyncProfileData(const std::string &one_profile_data) { std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex); m_profile_data.push_back(one_profile_data); - BroadcastEventIfUnique(eBroadcastBitProfileData, - new ProcessEventData(shared_from_this(), GetState())); + auto event_sp = CreateEventFromProcessState(eBroadcastBitProfileData); + BroadcastEventIfUnique(event_sp); } void Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, @@ -4734,27 +4932,26 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, if (!thread_plan_sp) { diagnostic_manager.PutString( - eDiagnosticSeverityError, - "RunThreadPlan called with empty thread plan."); + lldb::eSeverityError, "RunThreadPlan called with empty thread plan."); return eExpressionSetupError; } if (!thread_plan_sp->ValidatePlan(nullptr)) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "RunThreadPlan called with an invalid thread plan."); return eExpressionSetupError; } if (exe_ctx.GetProcessPtr() != this) { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "RunThreadPlan called on wrong process."); return eExpressionSetupError; } Thread *thread = exe_ctx.GetThreadPtr(); if (thread == nullptr) { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "RunThreadPlan called with invalid thread."); return eExpressionSetupError; } @@ -4789,7 +4986,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, if (m_private_state.GetValue() != eStateStopped) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "RunThreadPlan called while the private state was not stopped."); return eExpressionSetupError; } @@ -4803,7 +5000,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, selected_frame_sp = thread->GetSelectedFrame(DoNoSelectMostRelevantFrame); if (!selected_frame_sp) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "RunThreadPlan called without a selected frame on thread %d", thread_idx_id); return eExpressionSetupError; @@ -4814,7 +5011,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, // be smaller than the overall timeout. if (options.GetOneThreadTimeout() && options.GetTimeout() && *options.GetTimeout() < *options.GetOneThreadTimeout()) { - diagnostic_manager.PutString(eDiagnosticSeverityError, + diagnostic_manager.PutString(lldb::eSeverityError, "RunThreadPlan called with one thread " "timeout greater than total timeout"); return eExpressionSetupError; @@ -4942,7 +5139,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, Event *other_events = listener_sp->PeekAtNextEvent(); if (other_events != nullptr) { diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "RunThreadPlan called with pending events on the queue."); return eExpressionSetupError; } @@ -4985,7 +5182,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, Status resume_error = PrivateResume(); if (!resume_error.Success()) { diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "couldn't resume inferior the %d time: \"%s\".", num_resumes, resume_error.AsCString()); return_value = eExpressionSetupError; @@ -5001,7 +5198,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, "resume %" PRIu32 ", exiting.", num_resumes); - diagnostic_manager.Printf(eDiagnosticSeverityError, + diagnostic_manager.Printf(lldb::eSeverityError, "didn't get any event after resume %" PRIu32 ", exiting.", num_resumes); @@ -5037,7 +5234,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, } diagnostic_manager.Printf( - eDiagnosticSeverityError, + lldb::eSeverityError, "didn't get running event after initial resume, got %s instead.", StateAsCString(stop_state)); return_value = eExpressionSetupError; @@ -5095,7 +5292,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, const bool use_run_lock = false; Halt(clear_thread_plans, use_run_lock); return_value = eExpressionInterrupted; - diagnostic_manager.PutString(eDiagnosticSeverityRemark, + diagnostic_manager.PutString(lldb::eSeverityInfo, "execution halted by user interrupt."); LLDB_LOGF(log, "Process::RunThreadPlan(): Got interrupted by " "eBroadcastBitInterrupted, exiting."); @@ -5148,7 +5345,7 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx, event_to_broadcast_sp = event_sp; diagnostic_manager.PutString( - eDiagnosticSeverityError, + lldb::eSeverityError, "execution stopped with unexpected state."); return_value = eExpressionInterrupted; break; @@ -5679,30 +5876,32 @@ void Process::Flush() { lldb::addr_t Process::GetCodeAddressMask() { if (uint32_t num_bits_setting = GetVirtualAddressableBits()) - return ~((1ULL << num_bits_setting) - 1); + return AddressableBits::AddressableBitToMask(num_bits_setting); return m_code_address_mask; } lldb::addr_t Process::GetDataAddressMask() { if (uint32_t num_bits_setting = GetVirtualAddressableBits()) - return ~((1ULL << num_bits_setting) - 1); + return AddressableBits::AddressableBitToMask(num_bits_setting); return m_data_address_mask; } lldb::addr_t Process::GetHighmemCodeAddressMask() { if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits()) - return ~((1ULL << num_bits_setting) - 1); - if (m_highmem_code_address_mask) + return AddressableBits::AddressableBitToMask(num_bits_setting); + + if (m_highmem_code_address_mask != LLDB_INVALID_ADDRESS_MASK) return m_highmem_code_address_mask; return GetCodeAddressMask(); } lldb::addr_t Process::GetHighmemDataAddressMask() { if (uint32_t num_bits_setting = GetHighmemVirtualAddressableBits()) - return ~((1ULL << num_bits_setting) - 1); - if (m_highmem_data_address_mask) + return AddressableBits::AddressableBitToMask(num_bits_setting); + + if (m_highmem_data_address_mask != LLDB_INVALID_ADDRESS_MASK) return m_highmem_data_address_mask; return GetDataAddressMask(); } @@ -5865,7 +6064,9 @@ void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { if (!sc.module_sp) return; LanguageType language = sc.GetLanguage(); - if (language == eLanguageTypeUnknown) + if (language == eLanguageTypeUnknown || + language == lldb::eLanguageTypeAssembly || + language == lldb::eLanguageTypeMipsAssembler) return; LanguageSet plugins = PluginManager::GetAllTypeSystemSupportedLanguagesForTypes(); @@ -6319,38 +6520,76 @@ static bool AddDirtyPages(const MemoryRegionInfo ®ion, // ranges. static void AddRegion(const MemoryRegionInfo ®ion, bool try_dirty_pages, Process::CoreFileMemoryRanges &ranges) { - // Don't add empty ranges or ranges with no permissions. - if (region.GetRange().GetByteSize() == 0 || region.GetLLDBPermissions() == 0) + // Don't add empty ranges. + if (region.GetRange().GetByteSize() == 0) + return; + // Don't add ranges with no read permissions. + if ((region.GetLLDBPermissions() & lldb::ePermissionsReadable) == 0) return; if (try_dirty_pages && AddDirtyPages(region, ranges)) return; ranges.push_back(CreateCoreFileMemoryRange(region)); } +static void SaveOffRegionsWithStackPointers( + Process &process, const MemoryRegionInfos ®ions, + Process::CoreFileMemoryRanges &ranges, std::set<addr_t> &stack_ends) { + const bool try_dirty_pages = true; + + // Before we take any dump, we want to save off the used portions of the + // stacks and mark those memory regions as saved. This prevents us from saving + // the unused portion of the stack below the stack pointer. Saving space on + // the dump. + for (lldb::ThreadSP thread_sp : process.GetThreadList().Threads()) { + if (!thread_sp) + continue; + StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0); + if (!frame_sp) + continue; + RegisterContextSP reg_ctx_sp = frame_sp->GetRegisterContext(); + if (!reg_ctx_sp) + continue; + const addr_t sp = reg_ctx_sp->GetSP(); + const size_t red_zone = process.GetABI()->GetRedZoneSize(); + lldb_private::MemoryRegionInfo sp_region; + if (process.GetMemoryRegionInfo(sp, sp_region).Success()) { + const size_t stack_head = (sp - red_zone); + const size_t stack_size = sp_region.GetRange().GetRangeEnd() - stack_head; + sp_region.GetRange().SetRangeBase(stack_head); + sp_region.GetRange().SetByteSize(stack_size); + stack_ends.insert(sp_region.GetRange().GetRangeEnd()); + AddRegion(sp_region, try_dirty_pages, ranges); + } + } +} + // Save all memory regions that are not empty or have at least some permissions // for a full core file style. static void GetCoreFileSaveRangesFull(Process &process, const MemoryRegionInfos ®ions, - Process::CoreFileMemoryRanges &ranges) { + Process::CoreFileMemoryRanges &ranges, + std::set<addr_t> &stack_ends) { // Don't add only dirty pages, add full regions. const bool try_dirty_pages = false; for (const auto ®ion : regions) - AddRegion(region, try_dirty_pages, ranges); + if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0) + AddRegion(region, try_dirty_pages, ranges); } // Save only the dirty pages to the core file. Make sure the process has at // least some dirty pages, as some OS versions don't support reporting what // pages are dirty within an memory region. If no memory regions have dirty // page information fall back to saving out all ranges with write permissions. -static void -GetCoreFileSaveRangesDirtyOnly(Process &process, - const MemoryRegionInfos ®ions, - Process::CoreFileMemoryRanges &ranges) { +static void GetCoreFileSaveRangesDirtyOnly( + Process &process, const MemoryRegionInfos ®ions, + Process::CoreFileMemoryRanges &ranges, std::set<addr_t> &stack_ends) { + // Iterate over the regions and find all dirty pages. bool have_dirty_page_info = false; for (const auto ®ion : regions) { - if (AddDirtyPages(region, ranges)) + if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0 && + AddDirtyPages(region, ranges)) have_dirty_page_info = true; } @@ -6359,7 +6598,8 @@ GetCoreFileSaveRangesDirtyOnly(Process &process, // plug-in so fall back to any region with write access permissions. const bool try_dirty_pages = false; for (const auto ®ion : regions) - if (region.GetWritable() == MemoryRegionInfo::eYes) + if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0 && + region.GetWritable() == MemoryRegionInfo::eYes) AddRegion(region, try_dirty_pages, ranges); } } @@ -6372,43 +6612,18 @@ GetCoreFileSaveRangesDirtyOnly(Process &process, // dirty regions as this will make the core file smaller. If the process // doesn't support dirty regions, then it will fall back to adding the full // stack region. -static void -GetCoreFileSaveRangesStackOnly(Process &process, - const MemoryRegionInfos ®ions, - Process::CoreFileMemoryRanges &ranges) { +static void GetCoreFileSaveRangesStackOnly( + Process &process, const MemoryRegionInfos ®ions, + Process::CoreFileMemoryRanges &ranges, std::set<addr_t> &stack_ends) { + const bool try_dirty_pages = true; // Some platforms support annotating the region information that tell us that // it comes from a thread stack. So look for those regions first. - // Keep track of which stack regions we have added - std::set<addr_t> stack_bases; - - const bool try_dirty_pages = true; for (const auto ®ion : regions) { - if (region.IsStackMemory() == MemoryRegionInfo::eYes) { - stack_bases.insert(region.GetRange().GetRangeBase()); + // Save all the stack memory ranges not associated with a stack pointer. + if (stack_ends.count(region.GetRange().GetRangeEnd()) == 0 && + region.IsStackMemory() == MemoryRegionInfo::eYes) AddRegion(region, try_dirty_pages, ranges); - } - } - - // Also check with our threads and get the regions for their stack pointers - // and add those regions if not already added above. - for (lldb::ThreadSP thread_sp : process.GetThreadList().Threads()) { - if (!thread_sp) - continue; - StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0); - if (!frame_sp) - continue; - RegisterContextSP reg_ctx_sp = frame_sp->GetRegisterContext(); - if (!reg_ctx_sp) - continue; - const addr_t sp = reg_ctx_sp->GetSP(); - lldb_private::MemoryRegionInfo sp_region; - if (process.GetMemoryRegionInfo(sp, sp_region).Success()) { - // Only add this region if not already added above. If our stack pointer - // is pointing off in the weeds, we will want this range. - if (stack_bases.count(sp_region.GetRange().GetRangeBase()) == 0) - AddRegion(sp_region, try_dirty_pages, ranges); - } } } @@ -6420,23 +6635,27 @@ Status Process::CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style, return err; if (regions.empty()) return Status("failed to get any valid memory regions from the process"); + if (core_style == eSaveCoreUnspecified) + return Status("callers must set the core_style to something other than " + "eSaveCoreUnspecified"); + + std::set<addr_t> stack_ends; + SaveOffRegionsWithStackPointers(*this, regions, ranges, stack_ends); switch (core_style) { case eSaveCoreUnspecified: - err = Status("callers must set the core_style to something other than " - "eSaveCoreUnspecified"); break; case eSaveCoreFull: - GetCoreFileSaveRangesFull(*this, regions, ranges); + GetCoreFileSaveRangesFull(*this, regions, ranges, stack_ends); break; case eSaveCoreDirtyOnly: - GetCoreFileSaveRangesDirtyOnly(*this, regions, ranges); + GetCoreFileSaveRangesDirtyOnly(*this, regions, ranges, stack_ends); break; case eSaveCoreStackOnly: - GetCoreFileSaveRangesStackOnly(*this, regions, ranges); + GetCoreFileSaveRangesStackOnly(*this, regions, ranges, stack_ends); break; } @@ -6448,3 +6667,25 @@ Status Process::CalculateCoreFileSaveRanges(lldb::SaveCoreStyle core_style, return Status(); // Success! } + +void Process::SetAddressableBitMasks(AddressableBits bit_masks) { + uint32_t low_memory_addr_bits = bit_masks.GetLowmemAddressableBits(); + uint32_t high_memory_addr_bits = bit_masks.GetHighmemAddressableBits(); + + if (low_memory_addr_bits == 0 && high_memory_addr_bits == 0) + return; + + if (low_memory_addr_bits != 0) { + addr_t low_addr_mask = + AddressableBits::AddressableBitToMask(low_memory_addr_bits); + SetCodeAddressMask(low_addr_mask); + SetDataAddressMask(low_addr_mask); + } + + if (high_memory_addr_bits != 0) { + addr_t high_addr_mask = + AddressableBits::AddressableBitToMask(high_memory_addr_bits); + SetHighmemCodeAddressMask(high_addr_mask); + SetHighmemDataAddressMask(high_addr_mask); + } +} diff --git a/contrib/llvm-project/lldb/source/Target/ProcessTrace.cpp b/contrib/llvm-project/lldb/source/Target/ProcessTrace.cpp index 3a41f257627c..4718a7ca50a7 100644 --- a/contrib/llvm-project/lldb/source/Target/ProcessTrace.cpp +++ b/contrib/llvm-project/lldb/source/Target/ProcessTrace.cpp @@ -36,15 +36,16 @@ ProcessSP ProcessTrace::CreateInstance(TargetSP target_sp, bool can_connect) { if (can_connect) return nullptr; - return std::make_shared<ProcessTrace>(target_sp, listener_sp); + return std::make_shared<ProcessTrace>(target_sp, listener_sp, *crash_file); } bool ProcessTrace::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) { return plugin_specified_by_name; } -ProcessTrace::ProcessTrace(TargetSP target_sp, ListenerSP listener_sp) - : PostMortemProcess(target_sp, listener_sp) {} +ProcessTrace::ProcessTrace(TargetSP target_sp, ListenerSP listener_sp, + const FileSpec &core_file) + : PostMortemProcess(target_sp, listener_sp, core_file) {} ProcessTrace::~ProcessTrace() { Clear(); diff --git a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp index 13e101413a47..bc8081f4e3b3 100644 --- a/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp +++ b/contrib/llvm-project/lldb/source/Target/RegisterContextUnwind.cpp @@ -1401,7 +1401,7 @@ RegisterContextUnwind::SavedLocationForRegister( // it's still live in the actual register. Handle this specially. if (!have_unwindplan_regloc && return_address_reg.IsValid() && - IsFrameZero()) { + BehavesLikeZerothFrame()) { if (return_address_reg.GetAsKind(eRegisterKindLLDB) != LLDB_INVALID_REGNUM) { lldb_private::UnwindLLDB::RegisterLocation new_regloc; @@ -1555,12 +1555,12 @@ RegisterContextUnwind::SavedLocationForRegister( } if (unwindplan_regloc.IsSame()) { - if (!IsFrameZero() && + if (!m_all_registers_available && (regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_PC || regnum.GetAsKind(eRegisterKindGeneric) == LLDB_REGNUM_GENERIC_RA)) { UnwindLogMsg("register %s (%d) is marked as 'IsSame' - it is a pc or " - "return address reg on a non-zero frame -- treat as if we " - "have no information", + "return address reg on a frame which does not have all " + "registers available -- treat as if we have no information", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } else { @@ -1661,12 +1661,14 @@ RegisterContextUnwind::SavedLocationForRegister( unwindplan_registerkind); Value cfa_val = Scalar(m_cfa); cfa_val.SetValueType(Value::ValueType::LoadAddress); - Value result; - Status error; - if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, result, - &error)) { + llvm::Expected<Value> result = + dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr); + if (!result) { + LLDB_LOG_ERROR(log, result.takeError(), + "DWARF expression failed to evaluate: {0}"); + } else { addr_t val; - val = result.GetScalar().ULongLong(); + val = result->GetScalar().ULongLong(); if (unwindplan_regloc.IsDWARFExpression()) { regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred; regloc.location.inferred_value = val; @@ -2029,11 +2031,10 @@ bool RegisterContextUnwind::ReadFrameAddress( DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr); dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind( row_register_kind); - Value result; - Status error; - if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, - &error)) { - address = result.GetScalar().ULongLong(); + llvm::Expected<Value> result = + dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr); + if (result) { + address = result->GetScalar().ULongLong(); if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) address = abi_sp->FixCodeAddress(address); @@ -2042,7 +2043,7 @@ bool RegisterContextUnwind::ReadFrameAddress( return true; } UnwindLogMsg("Failed to set CFA value via DWARF expression: %s", - error.AsCString()); + llvm::toString(result.takeError()).c_str()); break; } case UnwindPlan::Row::FAValue::isRaSearch: { diff --git a/contrib/llvm-project/lldb/source/Target/RegisterFlags.cpp b/contrib/llvm-project/lldb/source/Target/RegisterFlags.cpp index b1669b85fd2f..976e03870ad9 100644 --- a/contrib/llvm-project/lldb/source/Target/RegisterFlags.cpp +++ b/contrib/llvm-project/lldb/source/Target/RegisterFlags.cpp @@ -12,17 +12,42 @@ #include "llvm/ADT/StringExtras.h" +#include <limits> #include <numeric> #include <optional> using namespace lldb_private; RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end) - : m_name(std::move(name)), m_start(start), m_end(end) { + : m_name(std::move(name)), m_start(start), m_end(end), + m_enum_type(nullptr) { assert(m_start <= m_end && "Start bit must be <= end bit."); } -void RegisterFlags::Field::log(Log *log) const { +RegisterFlags::Field::Field(std::string name, unsigned bit_position) + : m_name(std::move(name)), m_start(bit_position), m_end(bit_position), + m_enum_type(nullptr) {} + +RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end, + const FieldEnum *enum_type) + : m_name(std::move(name)), m_start(start), m_end(end), + m_enum_type(enum_type) { + if (m_enum_type) { + // Check that all values fit into this field. The XML parser will also + // do this check so at runtime nothing should fail this check. + // We can also make enums in C++ at compile time, which might fail this + // check, so we catch them before it makes it into a release. + uint64_t max_value = GetMaxValue(); + UNUSED_IF_ASSERT_DISABLED(max_value); + for (const auto &enumerator : m_enum_type->GetEnumerators()) { + UNUSED_IF_ASSERT_DISABLED(enumerator); + assert(enumerator.m_value <= max_value && + "Enumerator value exceeds maximum value for this field"); + } + } +} + +void RegisterFlags::Field::DumpToLog(Log *log) const { LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start, m_end); } @@ -53,11 +78,36 @@ unsigned RegisterFlags::Field::PaddingDistance(const Field &other) const { return lhs_start - rhs_end - 1; } -void RegisterFlags::SetFields(const std::vector<Field> &fields) { - // We expect that the XML processor will discard anything describing flags but - // with no fields. - assert(fields.size() && "Some fields must be provided."); +unsigned RegisterFlags::Field::GetSizeInBits(unsigned start, unsigned end) { + return end - start + 1; +} + +unsigned RegisterFlags::Field::GetSizeInBits() const { + return GetSizeInBits(m_start, m_end); +} + +uint64_t RegisterFlags::Field::GetMaxValue(unsigned start, unsigned end) { + uint64_t max = std::numeric_limits<uint64_t>::max(); + unsigned bits = GetSizeInBits(start, end); + // If the field is >= 64 bits the shift below would be undefined. + // We assume the GDB client has discarded any field that would fail this + // assert, it's only to check information we define directly in C++. + assert(bits <= 64 && "Cannot handle field with size > 64 bits"); + if (bits < 64) { + max = ((uint64_t)1 << bits) - 1; + } + return max; +} + +uint64_t RegisterFlags::Field::GetMaxValue() const { + return GetMaxValue(m_start, m_end); +} + +uint64_t RegisterFlags::Field::GetMask() const { + return GetMaxValue() << m_start; +} +void RegisterFlags::SetFields(const std::vector<Field> &fields) { // We expect that these are unsorted but do not overlap. // They could fill the register but may have gaps. std::vector<Field> provided_fields = fields; @@ -102,10 +152,10 @@ RegisterFlags::RegisterFlags(std::string id, unsigned size, SetFields(fields); } -void RegisterFlags::log(Log *log) const { +void RegisterFlags::DumpToLog(Log *log) const { LLDB_LOG(log, "ID: \"{0}\" Size: {1}", m_id.c_str(), m_size); for (const Field &field : m_fields) - field.log(log); + field.DumpToLog(log); } static StreamString FormatCell(const StreamString &content, @@ -190,7 +240,143 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const { return table; } -void RegisterFlags::ToXML(StreamString &strm) const { +// Print enums as: +// value = name, value2 = name2 +// Subject to the limits of the terminal width. +static void DumpEnumerators(StreamString &strm, size_t indent, + size_t current_width, uint32_t max_width, + const FieldEnum::Enumerators &enumerators) { + for (auto it = enumerators.cbegin(); it != enumerators.cend(); ++it) { + StreamString enumerator_strm; + // The first enumerator of a line doesn't need to be separated. + if (current_width != indent) + enumerator_strm << ' '; + + enumerator_strm.Printf("%" PRIu64 " = %s", it->m_value, it->m_name.c_str()); + + // Don't put "," after the last enumerator. + if (std::next(it) != enumerators.cend()) + enumerator_strm << ","; + + llvm::StringRef enumerator_string = enumerator_strm.GetString(); + // If printing the next enumerator would take us over the width, start + // a new line. However, if we're printing the first enumerator of this + // line, don't start a new one. Resulting in there being at least one per + // line. + // + // This means for very small widths we get: + // A: 0 = foo, + // 1 = bar + // Instead of: + // A: + // 0 = foo, + // 1 = bar + if ((current_width + enumerator_string.size() > max_width) && + current_width != indent) { + current_width = indent; + strm << '\n' << std::string(indent, ' '); + // We're going to a new line so we don't need a space before the + // name of the enumerator. + enumerator_string = enumerator_string.drop_front(); + } + + current_width += enumerator_string.size(); + strm << enumerator_string; + } +} + +std::string RegisterFlags::DumpEnums(uint32_t max_width) const { + StreamString strm; + bool printed_enumerators_once = false; + + for (const auto &field : m_fields) { + const FieldEnum *enum_type = field.GetEnum(); + if (!enum_type) + continue; + + const FieldEnum::Enumerators &enumerators = enum_type->GetEnumerators(); + if (enumerators.empty()) + continue; + + // Break between enumerators of different fields. + if (printed_enumerators_once) + strm << "\n\n"; + else + printed_enumerators_once = true; + + std::string name_string = field.GetName() + ": "; + size_t indent = name_string.size(); + size_t current_width = indent; + + strm << name_string; + + DumpEnumerators(strm, indent, current_width, max_width, enumerators); + } + + return strm.GetString().str(); +} + +void RegisterFlags::EnumsToXML(Stream &strm, llvm::StringSet<> &seen) const { + for (const Field &field : m_fields) + if (const FieldEnum *enum_type = field.GetEnum()) { + const std::string &id = enum_type->GetID(); + if (!seen.contains(id)) { + enum_type->ToXML(strm, GetSize()); + seen.insert(id); + } + } +} + +void FieldEnum::ToXML(Stream &strm, unsigned size) const { + // Example XML: + // <enum id="foo" size="4"> + // <evalue name="bar" value="1"/> + // </enum> + // Note that "size" is only emitted for GDB compatibility, LLDB does not need + // it. + + strm.Indent(); + strm << "<enum id=\"" << GetID() << "\" "; + // This is the size of the underlying enum type if this were a C type. + // In other words, the size of the register in bytes. + strm.Printf("size=\"%d\"", size); + + const Enumerators &enumerators = GetEnumerators(); + if (enumerators.empty()) { + strm << "/>\n"; + return; + } + + strm << ">\n"; + strm.IndentMore(); + for (const auto &enumerator : enumerators) { + strm.Indent(); + enumerator.ToXML(strm); + strm.PutChar('\n'); + } + strm.IndentLess(); + strm.Indent("</enum>\n"); +} + +void FieldEnum::Enumerator::ToXML(Stream &strm) const { + std::string escaped_name; + llvm::raw_string_ostream escape_strm(escaped_name); + llvm::printHTMLEscaped(m_name, escape_strm); + strm.Printf("<evalue name=\"%s\" value=\"%" PRIu64 "\"/>", + escaped_name.c_str(), m_value); +} + +void FieldEnum::Enumerator::DumpToLog(Log *log) const { + LLDB_LOG(log, " Name: \"{0}\" Value: {1}", m_name.c_str(), m_value); +} + +void FieldEnum::DumpToLog(Log *log) const { + LLDB_LOG(log, "ID: \"{0}\"", m_id.c_str()); + for (const auto &enumerator : GetEnumerators()) + enumerator.DumpToLog(log); +} + +void RegisterFlags::ToXML(Stream &strm) const { // Example XML: // <flags id="cpsr_flags" size="4"> // <field name="incorrect" start="0" end="0"/> @@ -213,8 +399,10 @@ void RegisterFlags::ToXML(StreamString &strm) const { strm.Indent("</flags>\n"); } -void RegisterFlags::Field::ToXML(StreamString &strm) const { - // Example XML: +void RegisterFlags::Field::ToXML(Stream &strm) const { + // Example XML with an enum: + // <field name="correct" start="0" end="0" type="some_enum"> + // Without: // <field name="correct" start="0" end="0"/> strm.Indent(); strm << "<field name=\""; @@ -225,5 +413,17 @@ void RegisterFlags::Field::ToXML(StreamString &strm) const { strm << escaped_name << "\" "; strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd()); + + if (const FieldEnum *enum_type = GetEnum()) + strm << " type=\"" << enum_type->GetID() << "\""; + strm << "/>"; } + +FieldEnum::FieldEnum(std::string id, const Enumerators &enumerators) + : m_id(id), m_enumerators(enumerators) { + for (const auto &enumerator : m_enumerators) { + UNUSED_IF_ASSERT_DISABLED(enumerator); + assert(enumerator.m_name.size() && "Enumerator name cannot be empty"); + } +}
\ No newline at end of file diff --git a/contrib/llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp b/contrib/llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp index 0bd6c9251c85..cac738ea67b4 100644 --- a/contrib/llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp +++ b/contrib/llvm-project/lldb/source/Target/RemoteAwarePlatform.cpp @@ -30,142 +30,29 @@ bool RemoteAwarePlatform::GetModuleSpec(const FileSpec &module_file_spec, } Status RemoteAwarePlatform::ResolveExecutable( - const ModuleSpec &module_spec, ModuleSP &exe_module_sp, + const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr) { - Status error; - // Nothing special to do here, just use the actual file and architecture - - char exe_path[PATH_MAX]; ModuleSpec resolved_module_spec(module_spec); + // The host platform can resolve the path more aggressively. if (IsHost()) { - // If we have "ls" as the exe_file, resolve the executable location based - // on the current path variables - if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { - resolved_module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); - resolved_module_spec.GetFileSpec().SetFile(exe_path, - FileSpec::Style::native); - FileSystem::Instance().Resolve(resolved_module_spec.GetFileSpec()); - } + FileSpec &resolved_file_spec = resolved_module_spec.GetFileSpec(); - if (!FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - FileSystem::Instance().ResolveExecutableLocation( - resolved_module_spec.GetFileSpec()); - - // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - - if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - error.Clear(); - else { - const uint32_t permissions = FileSystem::Instance().GetPermissions( - resolved_module_spec.GetFileSpec()); - if (permissions && (permissions & eFilePermissionsEveryoneR) == 0) - error.SetErrorStringWithFormat( - "executable '%s' is not readable", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - else - error.SetErrorStringWithFormat( - "unable to find executable for '%s'", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - } - } else { - if (m_remote_platform_sp) { - return GetCachedExecutable(resolved_module_spec, exe_module_sp, - module_search_paths_ptr); + if (!FileSystem::Instance().Exists(resolved_file_spec)) { + resolved_module_spec.GetFileSpec().SetFile(resolved_file_spec.GetPath(), + FileSpec::Style::native); + FileSystem::Instance().Resolve(resolved_file_spec); } - // We may connect to a process and use the provided executable (Don't use - // local $PATH). - - // Resolve any executable within a bundle on MacOSX - Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); - - if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) - error.Clear(); - else - error.SetErrorStringWithFormat("the platform is not currently " - "connected, and '%s' doesn't exist in " - "the system root.", - exe_path); - } - - if (error.Success()) { - if (resolved_module_spec.GetArchitecture().IsValid()) { - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); - if (error.Fail()) { - // If we failed, it may be because the vendor and os aren't known. If - // that is the case, try setting them to the host architecture and give - // it another try. - llvm::Triple &module_triple = - resolved_module_spec.GetArchitecture().GetTriple(); - bool is_vendor_specified = - (module_triple.getVendor() != llvm::Triple::UnknownVendor); - bool is_os_specified = - (module_triple.getOS() != llvm::Triple::UnknownOS); - if (!is_vendor_specified || !is_os_specified) { - const llvm::Triple &host_triple = - HostInfo::GetArchitecture(HostInfo::eArchKindDefault).GetTriple(); - - if (!is_vendor_specified) - module_triple.setVendorName(host_triple.getVendorName()); - if (!is_os_specified) - module_triple.setOSName(host_triple.getOSName()); - - error = ModuleList::GetSharedModule(resolved_module_spec, - exe_module_sp, module_search_paths_ptr, nullptr, nullptr); - } - } - - // TODO find out why exe_module_sp might be NULL - if (error.Fail() || !exe_module_sp || !exe_module_sp->GetObjectFile()) { - exe_module_sp.reset(); - error.SetErrorStringWithFormat( - "'%s' doesn't contain the architecture %s", - resolved_module_spec.GetFileSpec().GetPath().c_str(), - resolved_module_spec.GetArchitecture().GetArchitectureName()); - } - } else { - // No valid architecture was specified, ask the platform for the - // architectures that we should be using (in the correct order) and see - // if we can find a match that way - StreamString arch_names; - llvm::ListSeparator LS; - ArchSpec process_host_arch; - for (const ArchSpec &arch : - GetSupportedArchitectures(process_host_arch)) { - resolved_module_spec.GetArchitecture() = arch; - error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, - module_search_paths_ptr, nullptr, nullptr); - // Did we find an executable using one of the - if (error.Success()) { - if (exe_module_sp && exe_module_sp->GetObjectFile()) - break; - else - error.SetErrorToGenericError(); - } - - arch_names << LS << arch.GetArchitectureName(); - } - - if (error.Fail() || !exe_module_sp) { - if (FileSystem::Instance().Readable( - resolved_module_spec.GetFileSpec())) { - error.SetErrorStringWithFormatv( - "'{0}' doesn't contain any '{1}' platform architectures: {2}", - resolved_module_spec.GetFileSpec(), GetPluginName(), - arch_names.GetData()); - } else { - error.SetErrorStringWithFormat( - "'%s' is not readable", - resolved_module_spec.GetFileSpec().GetPath().c_str()); - } - } - } + if (!FileSystem::Instance().Exists(resolved_file_spec)) + FileSystem::Instance().ResolveExecutableLocation(resolved_file_spec); + } else if (m_remote_platform_sp) { + return GetCachedExecutable(resolved_module_spec, exe_module_sp, + module_search_paths_ptr); } - return error; + return Platform::ResolveExecutable(resolved_module_spec, exe_module_sp, + module_search_paths_ptr); } Status RemoteAwarePlatform::RunShellCommand( @@ -266,11 +153,11 @@ Status RemoteAwarePlatform::Unlink(const FileSpec &file_spec) { return Platform::Unlink(file_spec); } -bool RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, - uint64_t &high) { +llvm::ErrorOr<llvm::MD5::MD5Result> +RemoteAwarePlatform::CalculateMD5(const FileSpec &file_spec) { if (m_remote_platform_sp) - return m_remote_platform_sp->CalculateMD5(file_spec, low, high); - return Platform::CalculateMD5(file_spec, low, high); + return m_remote_platform_sp->CalculateMD5(file_spec); + return Platform::CalculateMD5(file_spec); } FileSpec RemoteAwarePlatform::GetRemoteWorkingDirectory() { diff --git a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp index 50cf01e63cd4..3a2b4d05b288 100644 --- a/contrib/llvm-project/lldb/source/Target/StackFrame.cpp +++ b/contrib/llvm-project/lldb/source/Target/StackFrame.cpp @@ -857,10 +857,11 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( "\"(%s) %s\" is not an array type", valobj_sp->GetTypeName().AsCString("<invalid type>"), var_expr_path_strm.GetData()); - } else if ( - static_cast<uint32_t>(child_index) >= - synthetic - ->GetNumChildren() /* synthetic does not have that many values */) { + } else if (static_cast<uint32_t>(child_index) >= + synthetic + ->GetNumChildrenIgnoringErrors() /* synthetic does + not have that + many values */) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( "array index %ld is not valid for \"(%s) %s\"", child_index, @@ -929,10 +930,9 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( "\"(%s) %s\" is not an array type", valobj_sp->GetTypeName().AsCString("<invalid type>"), var_expr_path_strm.GetData()); - } else if ( - static_cast<uint32_t>(child_index) >= - synthetic - ->GetNumChildren() /* synthetic does not have that many values */) { + } else if (static_cast<uint32_t>(child_index) >= + synthetic->GetNumChildrenIgnoringErrors() /* synthetic + does not have that many values */) { valobj_sp->GetExpressionPath(var_expr_path_strm); error.SetErrorStringWithFormat( "array index %ld is not valid for \"(%s) %s\"", child_index, @@ -1091,24 +1091,19 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) { m_flags.Set(GOT_FRAME_BASE); ExecutionContext exe_ctx(shared_from_this()); - Value expr_value; addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; if (!m_sc.function->GetFrameBaseExpression().IsAlwaysValidSingleExpr()) loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress( exe_ctx.GetTargetPtr()); - if (!m_sc.function->GetFrameBaseExpression().Evaluate( - &exe_ctx, nullptr, loclist_base_addr, nullptr, nullptr, - expr_value, &m_frame_base_error)) { - // We should really have an error if evaluate returns, but in case we - // don't, lets set the error to something at least. - if (m_frame_base_error.Success()) - m_frame_base_error.SetErrorString( - "Evaluation of the frame base expression failed."); - } else { - m_frame_base = expr_value.ResolveValue(&exe_ctx); - } + llvm::Expected<Value> expr_value = + m_sc.function->GetFrameBaseExpression().Evaluate( + &exe_ctx, nullptr, loclist_base_addr, nullptr, nullptr); + if (!expr_value) + m_frame_base_error = expr_value.takeError(); + else + m_frame_base = expr_value->ResolveValue(&exe_ctx); } else { m_frame_base_error.SetErrorString("No function in symbol context."); } @@ -1203,26 +1198,23 @@ bool StackFrame::IsArtificial() const { return m_stack_frame_kind == StackFrame::Kind::Artificial; } -lldb::LanguageType StackFrame::GetLanguage() { +SourceLanguage StackFrame::GetLanguage() { CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; if (cu) return cu->GetLanguage(); - return lldb::eLanguageTypeUnknown; + return {}; } -lldb::LanguageType StackFrame::GuessLanguage() { - LanguageType lang_type = GetLanguage(); +SourceLanguage StackFrame::GuessLanguage() { + SourceLanguage lang_type = GetLanguage(); if (lang_type == eLanguageTypeUnknown) { - SymbolContext sc = GetSymbolContext(eSymbolContextFunction - | eSymbolContextSymbol); - if (sc.function) { - lang_type = sc.function->GetMangled().GuessLanguage(); - } + SymbolContext sc = + GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol); + if (sc.function) + lang_type = LanguageType(sc.function->GetMangled().GuessLanguage()); else if (sc.symbol) - { - lang_type = sc.symbol->GetMangled().GuessLanguage(); - } + lang_type = SourceLanguage(sc.symbol->GetMangled().GuessLanguage()); } return lang_type; @@ -1302,7 +1294,7 @@ GetBaseExplainingDereference(const Instruction::Operand &operand, } return std::make_pair(nullptr, 0); } -} +} // namespace lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) { TargetSP target_sp = CalculateTarget(); @@ -1397,7 +1389,8 @@ ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, return parent; } - for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci) { + for (int ci = 0, ce = parent->GetNumChildrenIgnoringErrors(); ci != ce; + ++ci) { ValueObjectSP child_sp = parent->GetChildAtIndex(ci); if (!child_sp) { @@ -1799,7 +1792,6 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, return; ExecutionContext exe_ctx(shared_from_this()); - StreamString s; const FormatEntity::Entry *frame_format = nullptr; Target *target = exe_ctx.GetTargetPtr(); @@ -1921,7 +1913,7 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, size_t num_lines = target->GetSourceManager().DisplaySourceLinesWithLineNumbers( - m_sc.line_entry.file, start_line, m_sc.line_entry.column, + m_sc.line_entry.GetFile(), start_line, m_sc.line_entry.column, source_lines_before, source_lines_after, "->", &strm); if (num_lines != 0) have_source = true; diff --git a/contrib/llvm-project/lldb/source/Target/StackFrameList.cpp b/contrib/llvm-project/lldb/source/Target/StackFrameList.cpp index 2273e52e2e04..0cf9ce1bf043 100644 --- a/contrib/llvm-project/lldb/source/Target/StackFrameList.cpp +++ b/contrib/llvm-project/lldb/source/Target/StackFrameList.cpp @@ -884,9 +884,9 @@ void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { GetFrameAtIndex(GetSelectedFrameIndex(DoNoSelectMostRelevantFrame))); if (frame_sp) { SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); - if (sc.line_entry.file) + if (sc.line_entry.GetFile()) m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine( - sc.line_entry.file, sc.line_entry.line); + sc.line_entry.GetFile(), sc.line_entry.line); } } } @@ -966,9 +966,9 @@ size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, // Check for interruption here. If we're fetching arguments, this loop // can go slowly: Debugger &dbg = m_thread.GetProcess()->GetTarget().GetDebugger(); - if (INTERRUPT_REQUESTED(dbg, - "Interrupted dumping stack for thread {0:hex} with {1} shown.", - m_thread.GetID(), num_frames_displayed)) + if (INTERRUPT_REQUESTED( + dbg, "Interrupted dumping stack for thread {0:x} with {1} shown.", + m_thread.GetID(), num_frames_displayed)) break; diff --git a/contrib/llvm-project/lldb/source/Target/Statistics.cpp b/contrib/llvm-project/lldb/source/Target/Statistics.cpp index c739ac7058ca..583d1524881f 100644 --- a/contrib/llvm-project/lldb/source/Target/Statistics.cpp +++ b/contrib/llvm-project/lldb/source/Target/Statistics.cpp @@ -10,10 +10,13 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" +#include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" +#include "lldb/Utility/StructuredData.h" using namespace lldb; using namespace lldb_private; @@ -99,60 +102,96 @@ llvm::json::Value ConstStringStats::ToJSON() const { return obj; } -json::Value TargetStats::ToJSON(Target &target) { - CollectStats(target); +json::Value +TargetStats::ToJSON(Target &target, + const lldb_private::StatisticsOptions &options) { + json::Object target_metrics_json; + ProcessSP process_sp = target.GetProcessSP(); + const bool summary_only = options.GetSummaryOnly(); + const bool include_modules = options.GetIncludeModules(); + if (!summary_only) { + CollectStats(target); - json::Array json_module_uuid_array; - for (auto module_identifier : m_module_identifiers) - json_module_uuid_array.emplace_back(module_identifier); + json::Array json_module_uuid_array; + for (auto module_identifier : m_module_identifiers) + json_module_uuid_array.emplace_back(module_identifier); - json::Object target_metrics_json{ - {m_expr_eval.name, m_expr_eval.ToJSON()}, - {m_frame_var.name, m_frame_var.ToJSON()}, - {"moduleIdentifiers", std::move(json_module_uuid_array)}}; + target_metrics_json.try_emplace(m_expr_eval.name, m_expr_eval.ToJSON()); + target_metrics_json.try_emplace(m_frame_var.name, m_frame_var.ToJSON()); + if (include_modules) + target_metrics_json.try_emplace("moduleIdentifiers", + std::move(json_module_uuid_array)); - if (m_launch_or_attach_time && m_first_private_stop_time) { - double elapsed_time = - elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); - target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); - } - if (m_launch_or_attach_time && m_first_public_stop_time) { - double elapsed_time = - elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); - target_metrics_json.try_emplace("firstStopTime", elapsed_time); + if (m_launch_or_attach_time && m_first_private_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_private_stop_time); + target_metrics_json.try_emplace("launchOrAttachTime", elapsed_time); + } + if (m_launch_or_attach_time && m_first_public_stop_time) { + double elapsed_time = + elapsed(*m_launch_or_attach_time, *m_first_public_stop_time); + target_metrics_json.try_emplace("firstStopTime", elapsed_time); + } + target_metrics_json.try_emplace("targetCreateTime", + m_create_time.get().count()); + + json::Array breakpoints_array; + double totalBreakpointResolveTime = 0.0; + // Report both the normal breakpoint list and the internal breakpoint list. + for (int i = 0; i < 2; ++i) { + BreakpointList &breakpoints = target.GetBreakpointList(i == 1); + std::unique_lock<std::recursive_mutex> lock; + breakpoints.GetListMutex(lock); + size_t num_breakpoints = breakpoints.GetSize(); + for (size_t i = 0; i < num_breakpoints; i++) { + Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); + breakpoints_array.push_back(bp->GetStatistics()); + totalBreakpointResolveTime += bp->GetResolveTime().count(); + } + } + target_metrics_json.try_emplace("breakpoints", + std::move(breakpoints_array)); + target_metrics_json.try_emplace("totalBreakpointResolveTime", + totalBreakpointResolveTime); + + if (process_sp) { + UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); + if (unix_signals_sp) + target_metrics_json.try_emplace( + "signals", unix_signals_sp->GetHitCountStatistics()); + } } - target_metrics_json.try_emplace("targetCreateTime", - m_create_time.get().count()); - - json::Array breakpoints_array; - double totalBreakpointResolveTime = 0.0; - // Rport both the normal breakpoint list and the internal breakpoint list. - for (int i = 0; i < 2; ++i) { - BreakpointList &breakpoints = target.GetBreakpointList(i == 1); + + // Counting "totalSharedLibraryEventHitCount" from breakpoints of kind + // "shared-library-event". + { + uint32_t shared_library_event_breakpoint_hit_count = 0; + // The "shared-library-event" is only found in the internal breakpoint list. + BreakpointList &breakpoints = target.GetBreakpointList(/* internal */ true); std::unique_lock<std::recursive_mutex> lock; breakpoints.GetListMutex(lock); size_t num_breakpoints = breakpoints.GetSize(); for (size_t i = 0; i < num_breakpoints; i++) { Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); - breakpoints_array.push_back(bp->GetStatistics()); - totalBreakpointResolveTime += bp->GetResolveTime().count(); + if (strcmp(bp->GetBreakpointKind(), "shared-library-event") == 0) + shared_library_event_breakpoint_hit_count += bp->GetHitCount(); } + + target_metrics_json.try_emplace("totalSharedLibraryEventHitCount", + shared_library_event_breakpoint_hit_count); } - ProcessSP process_sp = target.GetProcessSP(); if (process_sp) { - UnixSignalsSP unix_signals_sp = process_sp->GetUnixSignals(); - if (unix_signals_sp) - target_metrics_json.try_emplace("signals", - unix_signals_sp->GetHitCountStatistics()); uint32_t stop_id = process_sp->GetStopID(); target_metrics_json.try_emplace("stopCount", stop_id); - } - target_metrics_json.try_emplace("breakpoints", std::move(breakpoints_array)); - target_metrics_json.try_emplace("totalBreakpointResolveTime", - totalBreakpointResolveTime); - target_metrics_json.try_emplace("sourceMapDeduceCount", m_source_map_deduce_count); + llvm::StringRef dyld_plugin_name; + if (process_sp->GetDynamicLoader()) + dyld_plugin_name = process_sp->GetDynamicLoader()->GetPluginName(); + target_metrics_json.try_emplace("dyldPluginName", dyld_plugin_name); + } + target_metrics_json.try_emplace("sourceMapDeduceCount", + m_source_map_deduce_count); return target_metrics_json; } @@ -183,8 +222,16 @@ void TargetStats::IncreaseSourceMapDeduceCount() { bool DebuggerStats::g_collecting_stats = false; -llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, - Target *target) { +llvm::json::Value DebuggerStats::ReportStatistics( + Debugger &debugger, Target *target, + const lldb_private::StatisticsOptions &options) { + + const bool summary_only = options.GetSummaryOnly(); + const bool load_all_debug_info = options.GetLoadAllDebugInfo(); + const bool include_targets = options.GetIncludeTargets(); + const bool include_modules = options.GetIncludeModules(); + const bool include_transcript = options.GetIncludeTranscript(); + json::Array json_targets; json::Array json_modules; double symtab_parse_time = 0.0; @@ -196,12 +243,7 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, uint32_t debug_index_loaded = 0; uint32_t debug_index_saved = 0; uint64_t debug_info_size = 0; - if (target) { - json_targets.emplace_back(target->ReportStatistics()); - } else { - for (const auto &target : debugger.GetTargetList().Targets()) - json_targets.emplace_back(target->ReportStatistics()); - } + std::vector<ModuleStats> modules; std::lock_guard<std::recursive_mutex> guard( Module::GetAllocationModuleCollectionMutex()); @@ -214,15 +256,6 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { Module *module = Module::GetAllocatedModuleAtIndex(image_idx); ModuleStats module_stat; - module_stat.identifier = (intptr_t)module; - module_stat.path = module->GetFileSpec().GetPath(); - if (ConstString object_name = module->GetObjectName()) { - module_stat.path.append(1, '('); - module_stat.path.append(object_name.GetStringRef().str()); - module_stat.path.append(1, ')'); - } - module_stat.uuid = module->GetUUID().GetAsString(); - module_stat.triple = module->GetArchitecture().GetTriple().str(); module_stat.symtab_parse_time = module->GetSymtabParseTime().get().count(); module_stat.symtab_index_time = module->GetSymtabIndexTime().get().count(); Symtab *symtab = module->GetSymtab(); @@ -236,13 +269,14 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, } SymbolFile *sym_file = module->GetSymbolFile(); if (sym_file) { - - if (sym_file->GetObjectFile() != module->GetObjectFile()) - module_stat.symfile_path = - sym_file->GetObjectFile()->GetFileSpec().GetPath(); - module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); - module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); - module_stat.debug_info_size = sym_file->GetDebugInfoSize(); + if (!summary_only) { + if (sym_file->GetObjectFile() != module->GetObjectFile()) + module_stat.symfile_path = + sym_file->GetObjectFile()->GetFileSpec().GetPath(); + ModuleList symbol_modules = sym_file->GetDebugInfoModules(); + for (const auto &symbol_module : symbol_modules.Modules()) + module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); + } module_stat.debug_info_index_loaded_from_cache = sym_file->GetDebugInfoIndexWasLoadedFromCache(); if (module_stat.debug_info_index_loaded_from_cache) @@ -251,9 +285,10 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, sym_file->GetDebugInfoIndexWasSavedToCache(); if (module_stat.debug_info_index_saved_to_cache) ++debug_index_saved; - ModuleList symbol_modules = sym_file->GetDebugInfoModules(); - for (const auto &symbol_module: symbol_modules.Modules()) - module_stat.symfile_modules.push_back((intptr_t)symbol_module.get()); + module_stat.debug_index_time = sym_file->GetDebugInfoIndexTime().count(); + module_stat.debug_parse_time = sym_file->GetDebugInfoParseTime().count(); + module_stat.debug_info_size = + sym_file->GetDebugInfoSize(load_all_debug_info); module_stat.symtab_stripped = module->GetObjectFile()->IsStripped(); if (module_stat.symtab_stripped) ++num_stripped_modules; @@ -283,18 +318,21 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, if (module_stat.debug_info_had_incomplete_types) ++num_modules_with_incomplete_types; - json_modules.emplace_back(module_stat.ToJSON()); + if (include_modules) { + module_stat.identifier = (intptr_t)module; + module_stat.path = module->GetFileSpec().GetPath(); + if (ConstString object_name = module->GetObjectName()) { + module_stat.path.append(1, '('); + module_stat.path.append(object_name.GetStringRef().str()); + module_stat.path.append(1, ')'); + } + module_stat.uuid = module->GetUUID().GetAsString(); + module_stat.triple = module->GetArchitecture().GetTriple().str(); + json_modules.emplace_back(module_stat.ToJSON()); + } } - ConstStringStats const_string_stats; - json::Object json_memory{ - {"strings", const_string_stats.ToJSON()}, - }; - json::Object global_stats{ - {"targets", std::move(json_targets)}, - {"modules", std::move(json_modules)}, - {"memory", std::move(json_memory)}, {"totalSymbolTableParseTime", symtab_parse_time}, {"totalSymbolTableIndexTime", symtab_index_time}, {"totalSymbolTablesLoadedFromCache", symtabs_loaded}, @@ -307,9 +345,66 @@ llvm::json::Value DebuggerStats::ReportStatistics(Debugger &debugger, {"totalModuleCount", num_modules}, {"totalModuleCountHasDebugInfo", num_modules_has_debug_info}, {"totalModuleCountWithVariableErrors", num_modules_with_variable_errors}, - {"totalModuleCountWithIncompleteTypes", num_modules_with_incomplete_types}, + {"totalModuleCountWithIncompleteTypes", + num_modules_with_incomplete_types}, {"totalDebugInfoEnabled", num_debug_info_enabled_modules}, {"totalSymbolTableStripped", num_stripped_modules}, }; + + if (include_targets) { + if (target) { + json_targets.emplace_back(target->ReportStatistics(options)); + } else { + for (const auto &target : debugger.GetTargetList().Targets()) + json_targets.emplace_back(target->ReportStatistics(options)); + } + global_stats.try_emplace("targets", std::move(json_targets)); + } + + ConstStringStats const_string_stats; + json::Object json_memory{ + {"strings", const_string_stats.ToJSON()}, + }; + global_stats.try_emplace("memory", std::move(json_memory)); + if (!summary_only) { + json::Value cmd_stats = debugger.GetCommandInterpreter().GetStatistics(); + global_stats.try_emplace("commands", std::move(cmd_stats)); + } + + if (include_modules) { + global_stats.try_emplace("modules", std::move(json_modules)); + } + + if (include_transcript) { + // When transcript is available, add it to the to-be-returned statistics. + // + // NOTE: + // When the statistics is polled by an LLDB command: + // - The transcript in the returned statistics *will NOT* contain the + // returned statistics itself (otherwise infinite recursion). + // - The returned statistics *will* be written to the internal transcript + // buffer. It *will* appear in the next statistcs or transcript poll. + // + // For example, let's say the following commands are run in order: + // - "version" + // - "statistics dump" <- call it "A" + // - "statistics dump" <- call it "B" + // The output of "A" will contain the transcript of "version" and + // "statistics dump" (A), with the latter having empty output. The output + // of B will contain the trascnript of "version", "statistics dump" (A), + // "statistics dump" (B), with A's output populated and B's output empty. + const StructuredData::Array &transcript = + debugger.GetCommandInterpreter().GetTranscript(); + if (transcript.GetSize() != 0) { + std::string buffer; + llvm::raw_string_ostream ss(buffer); + json::OStream json_os(ss); + transcript.Serialize(json_os); + if (auto json_transcript = llvm::json::parse(ss.str())) + global_stats.try_emplace("transcript", + std::move(json_transcript.get())); + } + } + return std::move(global_stats); } diff --git a/contrib/llvm-project/lldb/source/Target/StopInfo.cpp b/contrib/llvm-project/lldb/source/Target/StopInfo.cpp index 3b65d661c1ab..95f78056b164 100644 --- a/contrib/llvm-project/lldb/source/Target/StopInfo.cpp +++ b/contrib/llvm-project/lldb/source/Target/StopInfo.cpp @@ -987,8 +987,10 @@ protected: // Don't stop if the watched region value is unmodified, and // this is a Modify-type watchpoint. - if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx)) + if (m_should_stop && !wp_sp->WatchedValueReportable(exe_ctx)) { + wp_sp->UndoHitCount(); m_should_stop = false; + } // Finally, if we are going to stop, print out the new & old values: if (m_should_stop) { diff --git a/contrib/llvm-project/lldb/source/Target/Target.cpp b/contrib/llvm-project/lldb/source/Target/Target.cpp index e969340fdf1e..ec0da8a1378a 100644 --- a/contrib/llvm-project/lldb/source/Target/Target.cpp +++ b/contrib/llvm-project/lldb/source/Target/Target.cpp @@ -43,6 +43,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" @@ -86,8 +87,8 @@ const Target::Arch &Target::Arch::operator=(const ArchSpec &spec) { return *this; } -ConstString &Target::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.target"); +llvm::StringRef Target::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.target"); return class_name; } @@ -95,7 +96,7 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp, bool is_dummy_target) : TargetProperties(this), Broadcaster(debugger.GetBroadcasterManager(), - Target::GetStaticBroadcasterClass().AsCString()), + Target::GetStaticBroadcasterClass().str()), ExecutionContextScope(), m_debugger(debugger), m_platform_sp(platform_sp), m_mutex(), m_arch(target_arch), m_images(this), m_section_load_history(), m_breakpoint_list(false), m_internal_breakpoint_list(true), @@ -503,7 +504,7 @@ BreakpointSP Target::CreateBreakpoint( if (skip_prologue == eLazyBoolCalculate) skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); + language = GetLanguage().AsLanguageType(); BreakpointResolverSP resolver_sp(new BreakpointResolverName( nullptr, func_name, func_name_type_mask, language, Breakpoint::Exact, @@ -529,7 +530,7 @@ Target::CreateBreakpoint(const FileSpecList *containingModules, if (skip_prologue == eLazyBoolCalculate) skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); + language = GetLanguage().AsLanguageType(); BreakpointResolverSP resolver_sp( new BreakpointResolverName(nullptr, func_names, func_name_type_mask, @@ -558,7 +559,7 @@ Target::CreateBreakpoint(const FileSpecList *containingModules, skip_prologue = eLazyBoolNo; } if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); + language = GetLanguage().AsLanguageType(); BreakpointResolverSP resolver_sp(new BreakpointResolverName( nullptr, func_names, num_names, func_name_type_mask, language, offset, @@ -840,7 +841,7 @@ static bool CheckIfWatchpointsSupported(Target *target, Status &error) { if (!num_supported_hardware_watchpoints) return true; - if (num_supported_hardware_watchpoints == 0) { + if (*num_supported_hardware_watchpoints == 0) { error.SetErrorStringWithFormat( "Target supports (%u) hardware watchpoint slots.\n", *num_supported_hardware_watchpoints); @@ -1568,14 +1569,8 @@ bool Target::SetArchitecture(const ArchSpec &arch_spec, bool set_platform, if (m_arch.GetSpec().IsCompatibleMatch(other)) { compatible_local_arch = true; - bool arch_changed, vendor_changed, os_changed, os_ver_changed, - env_changed; - m_arch.GetSpec().PiecewiseTripleCompare(other, arch_changed, - vendor_changed, os_changed, - os_ver_changed, env_changed); - - if (!arch_changed && !vendor_changed && !os_changed && !env_changed) + if (m_arch.GetSpec().GetTriple() == other.GetTriple()) replace_local_arch = false; } } @@ -2419,8 +2414,7 @@ llvm::Expected<lldb::TypeSystemSP> Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language, bool create_on_demand) { if (!m_valid) - return llvm::make_error<llvm::StringError>("Invalid Target", - llvm::inconvertibleErrorCode()); + return llvm::createStringError("Invalid Target"); if (language == eLanguageTypeMipsAssembler // GNU AS and LLVM use it for all // assembly code @@ -2433,9 +2427,8 @@ Target::GetScratchTypeSystemForLanguage(lldb::LanguageType language, // target language. } else { if (languages_for_expressions.Empty()) - return llvm::make_error<llvm::StringError>( - "No expression support for any languages", - llvm::inconvertibleErrorCode()); + return llvm::createStringError( + "No expression support for any languages"); language = (LanguageType)languages_for_expressions.bitvector.find_first(); } } @@ -2509,15 +2502,16 @@ Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) { } UserExpression *Target::GetUserExpressionForLanguage( - llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, + llvm::StringRef expr, llvm::StringRef prefix, SourceLanguage language, Expression::ResultType desired_type, const EvaluateExpressionOptions &options, ValueObject *ctx_obj, Status &error) { - auto type_system_or_err = GetScratchTypeSystemForLanguage(language); + auto type_system_or_err = + GetScratchTypeSystemForLanguage(language.AsLanguageType()); if (auto err = type_system_or_err.takeError()) { error.SetErrorStringWithFormat( "Could not find type system for language %s: %s", - Language::GetNameForLanguageType(language), + Language::GetNameForLanguageType(language.AsLanguageType()), llvm::toString(std::move(err)).c_str()); return nullptr; } @@ -2526,7 +2520,7 @@ UserExpression *Target::GetUserExpressionForLanguage( if (!ts) { error.SetErrorStringWithFormat( "Type system for language %s is no longer live", - Language::GetNameForLanguageType(language)); + language.GetDescription().data()); return nullptr; } @@ -2535,7 +2529,7 @@ UserExpression *Target::GetUserExpressionForLanguage( if (!user_expr) error.SetErrorStringWithFormat( "Could not create an expression for language %s", - Language::GetNameForLanguageType(language)); + language.GetDescription().data()); return user_expr; } @@ -2578,23 +2572,20 @@ Target::CreateUtilityFunction(std::string expression, std::string name, return type_system_or_err.takeError(); auto ts = *type_system_or_err; if (!ts) - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( llvm::StringRef("Type system for language ") + - Language::GetNameForLanguageType(language) + - llvm::StringRef(" is no longer live"), - llvm::inconvertibleErrorCode()); + Language::GetNameForLanguageType(language) + + llvm::StringRef(" is no longer live")); std::unique_ptr<UtilityFunction> utility_fn = ts->CreateUtilityFunction(std::move(expression), std::move(name)); if (!utility_fn) - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( llvm::StringRef("Could not create an expression for language") + - Language::GetNameForLanguageType(language), - llvm::inconvertibleErrorCode()); + Language::GetNameForLanguageType(language)); DiagnosticManager diagnostics; if (!utility_fn->Install(diagnostics, exe_ctx)) - return llvm::make_error<llvm::StringError>(diagnostics.GetString(), - llvm::inconvertibleErrorCode()); + return llvm::createStringError(diagnostics.GetString()); return std::move(utility_fn); } @@ -2625,8 +2616,7 @@ void Target::SetDefaultArchitecture(const ArchSpec &arch) { llvm::Error Target::SetLabel(llvm::StringRef label) { size_t n = LLDB_INVALID_INDEX32; if (llvm::to_integer(label, n)) - return llvm::make_error<llvm::StringError>( - "Cannot use integer as target label.", llvm::inconvertibleErrorCode()); + return llvm::createStringError("Cannot use integer as target label."); TargetList &targets = GetDebugger().GetTargetList(); for (size_t i = 0; i < targets.GetNumTargets(); i++) { TargetSP target_sp = targets.GetTargetAtIndex(i); @@ -2794,15 +2784,13 @@ llvm::Expected<lldb_private::Address> Target::GetEntryPointAddress() { // We haven't found the entry point address. Return an appropriate error. if (!has_primary_executable) - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "No primary executable found and could not find entry point address in " - "any executable module", - llvm::inconvertibleErrorCode()); + "any executable module"); - return llvm::make_error<llvm::StringError>( + return llvm::createStringError( "Could not find entry point address for primary executable module \"" + - exe_module->GetFileSpec().GetFilename().GetStringRef() + "\"", - llvm::inconvertibleErrorCode()); + exe_module->GetFileSpec().GetFilename().GetStringRef() + "\""); } lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr, @@ -4233,28 +4221,21 @@ void TargetProperties::UpdateLaunchInfoFromProperties() { DisableSTDIOValueChangedCallback(); } -bool TargetProperties::GetInjectLocalVariables( - ExecutionContext *exe_ctx) const { +std::optional<bool> TargetProperties::GetExperimentalPropertyValue( + size_t prop_idx, ExecutionContext *exe_ctx) const { const Property *exp_property = m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx); OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); if (exp_values) - return exp_values - ->GetPropertyAtIndexAs<bool>(ePropertyInjectLocalVars, exe_ctx) - .value_or(true); - else - return true; + return exp_values->GetPropertyAtIndexAs<bool>(prop_idx, exe_ctx); + return std::nullopt; } -void TargetProperties::SetInjectLocalVariables(ExecutionContext *exe_ctx, - bool b) { - const Property *exp_property = - m_collection_sp->GetPropertyAtIndex(ePropertyExperimental, exe_ctx); - OptionValueProperties *exp_values = - exp_property->GetValue()->GetAsProperties(); - if (exp_values) - exp_values->SetPropertyAtIndex(ePropertyInjectLocalVars, true, exe_ctx); +bool TargetProperties::GetInjectLocalVariables( + ExecutionContext *exe_ctx) const { + return GetExperimentalPropertyValue(ePropertyInjectLocalVars, exe_ctx) + .value_or(true); } ArchSpec TargetProperties::GetDefaultArchitecture() const { @@ -4658,9 +4639,9 @@ void TargetProperties::SetStandardErrorPath(llvm::StringRef path) { SetPropertyAtIndex(idx, path); } -LanguageType TargetProperties::GetLanguage() const { +SourceLanguage TargetProperties::GetLanguage() const { const uint32_t idx = ePropertyLanguage; - return GetPropertyAtIndexAs<LanguageType>(idx, {}); + return {GetPropertyAtIndexAs<LanguageType>(idx, {})}; } llvm::StringRef TargetProperties::GetExpressionPrefixContents() { @@ -4962,4 +4943,7 @@ std::recursive_mutex &Target::GetAPIMutex() { } /// Get metrics associated with this target in JSON format. -llvm::json::Value Target::ReportStatistics() { return m_stats.ToJSON(*this); } +llvm::json::Value +Target::ReportStatistics(const lldb_private::StatisticsOptions &options) { + return m_stats.ToJSON(*this, options); +} diff --git a/contrib/llvm-project/lldb/source/Target/TargetList.cpp b/contrib/llvm-project/lldb/source/Target/TargetList.cpp index 121b6253d2a5..10467753666f 100644 --- a/contrib/llvm-project/lldb/source/Target/TargetList.cpp +++ b/contrib/llvm-project/lldb/source/Target/TargetList.cpp @@ -29,15 +29,15 @@ using namespace lldb; using namespace lldb_private; -ConstString &TargetList::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.targetList"); +llvm::StringRef TargetList::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.targetList"); return class_name; } // TargetList constructor TargetList::TargetList(Debugger &debugger) : Broadcaster(debugger.GetBroadcasterManager(), - TargetList::GetStaticBroadcasterClass().AsCString()), + TargetList::GetStaticBroadcasterClass().str()), m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) { CheckInWithManager(); } @@ -532,9 +532,13 @@ void TargetList::SetSelectedTarget(uint32_t index) { } void TargetList::SetSelectedTarget(const TargetSP &target_sp) { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - auto it = llvm::find(m_target_list, target_sp); - SetSelectedTargetInternal(std::distance(m_target_list.begin(), it)); + // Don't allow an invalid target shared pointer or a target that has been + // destroyed to become the selected target. + if (target_sp && target_sp->IsValid()) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + auto it = llvm::find(m_target_list, target_sp); + SetSelectedTargetInternal(std::distance(m_target_list.begin(), it)); + } } lldb::TargetSP TargetList::GetSelectedTarget() { diff --git a/contrib/llvm-project/lldb/source/Target/TargetProperties.td b/contrib/llvm-project/lldb/source/Target/TargetProperties.td index d2fccdb7b9b3..7f79218e0a6a 100644 --- a/contrib/llvm-project/lldb/source/Target/TargetProperties.td +++ b/contrib/llvm-project/lldb/source/Target/TargetProperties.td @@ -311,3 +311,9 @@ let Definition = "thread" in { DefaultUnsignedValue<600000>, Desc<"Maximum number of frames to backtrace.">; } + +let Definition = "language" in { + def EnableFilterForLineBreakpoints: Property<"enable-filter-for-line-breakpoints", "Boolean">, + DefaultTrue, + Desc<"If true, allow Language plugins to filter locations when setting breakpoints by line number or regex.">; +} diff --git a/contrib/llvm-project/lldb/source/Target/Thread.cpp b/contrib/llvm-project/lldb/source/Target/Thread.cpp index 8ae2179c1281..e75f5a356cec 100644 --- a/contrib/llvm-project/lldb/source/Target/Thread.cpp +++ b/contrib/llvm-project/lldb/source/Target/Thread.cpp @@ -205,15 +205,15 @@ Thread::ThreadEventData::GetStackFrameFromEvent(const Event *event_ptr) { // Thread class -ConstString &Thread::GetStaticBroadcasterClass() { - static ConstString class_name("lldb.thread"); +llvm::StringRef Thread::GetStaticBroadcasterClass() { + static constexpr llvm::StringLiteral class_name("lldb.thread"); return class_name; } Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) : ThreadProperties(false), UserID(tid), Broadcaster(process.GetTarget().GetDebugger().GetBroadcasterManager(), - Thread::GetStaticBroadcasterClass().AsCString()), + Thread::GetStaticBroadcasterClass().str()), m_process_wp(process.shared_from_this()), m_stop_info_sp(), m_stop_info_stop_id(0), m_stop_info_override_stop_id(0), m_should_run_before_public_stop(false), @@ -221,7 +221,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) : process.GetNextThreadIndexID(tid)), m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(), - m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), + m_prev_framezero_pc(), m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning), m_unwinder_up(), m_destroy_called(false), m_override_should_notify(eLazyBoolCalculate), @@ -250,6 +250,7 @@ void Thread::DestroyThread() { std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); m_curr_frames_sp.reset(); m_prev_frames_sp.reset(); + m_prev_framezero_pc.reset(); } void Thread::BroadcastSelectedFrameChange(StackID &new_frame_id) { @@ -301,10 +302,10 @@ bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx, SymbolContext frame_sc( frame_sp->GetSymbolContext(eSymbolContextLineEntry)); const Debugger &debugger = GetProcess()->GetTarget().GetDebugger(); - if (debugger.GetUseExternalEditor() && frame_sc.line_entry.file && + if (debugger.GetUseExternalEditor() && frame_sc.line_entry.GetFile() && frame_sc.line_entry.line != 0) { if (llvm::Error e = Host::OpenFileInExternalEditor( - debugger.GetExternalEditor(), frame_sc.line_entry.file, + debugger.GetExternalEditor(), frame_sc.line_entry.GetFile(), frame_sc.line_entry.line)) { LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), "OpenFileInExternalEditor failed: {0}"); @@ -422,6 +423,12 @@ lldb::StopInfoSP Thread::GetPrivateStopInfo(bool calculate) { } } } + + // If we were resuming the process and it was interrupted, + // return no stop reason. This thread would like to resume. + if (m_stop_info_sp && m_stop_info_sp->WasContinueInterrupted(*this)) + return {}; + return m_stop_info_sp; } @@ -1408,16 +1415,22 @@ StackFrameListSP Thread::GetStackFrameList() { return m_curr_frames_sp; } +std::optional<addr_t> Thread::GetPreviousFrameZeroPC() { + return m_prev_framezero_pc; +} + void Thread::ClearStackFrames() { std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); GetUnwinder().Clear(); + m_prev_framezero_pc.reset(); + if (RegisterContextSP reg_ctx_sp = GetRegisterContext()) + m_prev_framezero_pc = reg_ctx_sp->GetPC(); // Only store away the old "reference" StackFrameList if we got all its // frames: // FIXME: At some point we can try to splice in the frames we have fetched - // into - // the new frame as we make it, but let's not try that now. + // into the new frame as we make it, but let's not try that now. if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched()) m_prev_frames_sp.swap(m_curr_frames_sp); m_curr_frames_sp.reset(); @@ -1740,10 +1753,10 @@ size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, if (frame_sp) { SymbolContext frame_sc( frame_sp->GetSymbolContext(eSymbolContextLineEntry)); - if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) { + if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.GetFile()) { if (llvm::Error e = Host::OpenFileInExternalEditor( target->GetDebugger().GetExternalEditor(), - frame_sc.line_entry.file, frame_sc.line_entry.line)) { + frame_sc.line_entry.GetFile(), frame_sc.line_entry.line)) { LLDB_LOG_ERROR(GetLog(LLDBLog::Host), std::move(e), "OpenFileInExternalEditor failed: {0}"); } diff --git a/contrib/llvm-project/lldb/source/Target/ThreadList.cpp b/contrib/llvm-project/lldb/source/Target/ThreadList.cpp index 03e8daedff12..1a2d7dd61c77 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadList.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadList.cpp @@ -23,7 +23,7 @@ using namespace lldb; using namespace lldb_private; -ThreadList::ThreadList(Process *process) +ThreadList::ThreadList(Process &process) : ThreadCollection(), m_process(process), m_stop_id(0), m_selected_tid(LLDB_INVALID_THREAD_ID) {} @@ -36,14 +36,13 @@ ThreadList::ThreadList(const ThreadList &rhs) const ThreadList &ThreadList::operator=(const ThreadList &rhs) { if (this != &rhs) { - // Lock both mutexes to make sure neither side changes anyone on us while - // the assignment occurs - std::lock(GetMutex(), rhs.GetMutex()); - std::lock_guard<std::recursive_mutex> guard(GetMutex(), std::adopt_lock); - std::lock_guard<std::recursive_mutex> rhs_guard(rhs.GetMutex(), - std::adopt_lock); - - m_process = rhs.m_process; + // We only allow assignments between thread lists describing the same + // process. Same process implies same mutex, which means it's enough to lock + // just the current object. + assert(&m_process == &rhs.m_process); + assert(&GetMutex() == &rhs.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + m_stop_id = rhs.m_stop_id; m_threads = rhs.m_threads; m_selected_tid = rhs.m_selected_tid; @@ -84,7 +83,7 @@ uint32_t ThreadList::GetSize(bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); return m_threads.size(); } @@ -92,7 +91,7 @@ ThreadSP ThreadList::GetThreadAtIndex(uint32_t idx, bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; if (idx < m_threads.size()) @@ -104,7 +103,7 @@ ThreadSP ThreadList::FindThreadByID(lldb::tid_t tid, bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; uint32_t idx = 0; @@ -122,7 +121,7 @@ ThreadSP ThreadList::FindThreadByProtocolID(lldb::tid_t tid, bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; uint32_t idx = 0; @@ -140,7 +139,7 @@ ThreadSP ThreadList::RemoveThreadByID(lldb::tid_t tid, bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; uint32_t idx = 0; @@ -160,7 +159,7 @@ ThreadSP ThreadList::RemoveThreadByProtocolID(lldb::tid_t tid, std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; uint32_t idx = 0; @@ -210,7 +209,7 @@ ThreadSP ThreadList::FindThreadByIndexID(uint32_t index_id, bool can_update) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); if (can_update) - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); ThreadSP thread_sp; const uint32_t num_threads = m_threads.size(); @@ -241,7 +240,7 @@ bool ThreadList::ShouldStop(Event *event_ptr) { // Scope for locker std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); for (lldb::ThreadSP thread_sp : m_threads) { // This is an optimization... If we didn't let a thread run in between // the previous stop and this one, we shouldn't have to consult it for @@ -377,7 +376,7 @@ Vote ThreadList::ShouldReportStop(Event *event_ptr) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); Vote result = eVoteNoOpinion; - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); collection::iterator pos, end = m_threads.end(); Log *log = GetLog(LLDBLog::Step); @@ -425,7 +424,7 @@ Vote ThreadList::ShouldReportStop(Event *event_ptr) { void ThreadList::SetShouldReportStop(Vote vote) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); collection::iterator pos, end = m_threads.end(); for (pos = m_threads.begin(); pos != end; ++pos) { ThreadSP thread_sp(*pos); @@ -438,7 +437,7 @@ Vote ThreadList::ShouldReportRun(Event *event_ptr) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); Vote result = eVoteNoOpinion; - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); collection::iterator pos, end = m_threads.end(); // Run through the threads and ask whether we should report this event. The @@ -486,7 +485,7 @@ void ThreadList::Destroy() { void ThreadList::RefreshStateAfterStop() { std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) @@ -515,7 +514,7 @@ bool ThreadList::WillResume() { // they are. std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); + m_process.UpdateThreadListIfNeeded(); collection::iterator pos, end = m_threads.end(); @@ -546,13 +545,13 @@ bool ThreadList::WillResume() { if (log && log->GetVerbose()) LLDB_LOGF(log, "Turning on notification of new threads while single " "stepping a thread."); - m_process->StartNoticingNewThreads(); + m_process.StartNoticingNewThreads(); } else { Log *log = GetLog(LLDBLog::Step); if (log && log->GetVerbose()) LLDB_LOGF(log, "Turning off notification of new threads while single " "stepping a thread."); - m_process->StopNoticingNewThreads(); + m_process.StopNoticingNewThreads(); } // Give all the threads that are likely to run a last chance to set up their @@ -575,7 +574,7 @@ bool ThreadList::WillResume() { ThreadList run_me_only_list(m_process); - run_me_only_list.SetStopID(m_process->GetStopID()); + run_me_only_list.SetStopID(m_process.GetStopID()); // One or more threads might want to "Stop Others". We want to handle all // those requests first. And if there is a thread that wanted to "resume @@ -736,11 +735,13 @@ void ThreadList::NotifySelectedThreadChanged(lldb::tid_t tid) { void ThreadList::Update(ThreadList &rhs) { if (this != &rhs) { - // Lock both mutexes to make sure neither side changes anyone on us while - // the assignment occurs - std::scoped_lock<std::recursive_mutex, std::recursive_mutex> guard(GetMutex(), rhs.GetMutex()); + // We only allow assignments between thread lists describing the same + // process. Same process implies same mutex, which means it's enough to lock + // just the current object. + assert(&m_process == &rhs.m_process); + assert(&GetMutex() == &rhs.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process = rhs.m_process; m_stop_id = rhs.m_stop_id; m_threads.swap(rhs.m_threads); m_selected_tid = rhs.m_selected_tid; @@ -784,7 +785,7 @@ void ThreadList::Flush() { } std::recursive_mutex &ThreadList::GetMutex() const { - return m_process->m_thread_mutex; + return m_process.m_thread_mutex; } ThreadList::ExpressionExecutionThreadPusher::ExpressionExecutionThreadPusher( diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp index d6de6b3c3cf0..dfcb67eb1902 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanPython.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/Interfaces/ScriptedThreadPlanInterface.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" @@ -32,6 +33,26 @@ ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, eVoteNoOpinion, eVoteNoOpinion), m_class_name(class_name), m_args_data(args_data), m_did_push(false), m_stop_others(false) { + ScriptInterpreter *interpreter = GetScriptInterpreter(); + if (!interpreter) { + SetPlanComplete(false); + // FIXME: error handling + // error.SetErrorStringWithFormat( + // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__, + // "Couldn't get script interpreter"); + return; + } + + m_interface = interpreter->CreateScriptedThreadPlanInterface(); + if (!m_interface) { + SetPlanComplete(false); + // FIXME: error handling + // error.SetErrorStringWithFormat( + // "ThreadPlanPython::%s () - ERROR: %s", __FUNCTION__, + // "Script interpreter couldn't create Scripted Thread Plan Interface"); + return; + } + SetIsControllingPlan(true); SetOkayToDiscard(true); SetPrivate(false); @@ -60,13 +81,14 @@ void ThreadPlanPython::DidPush() { // We set up the script side in DidPush, so that it can push other plans in // the constructor, and doesn't have to care about the details of DidPush. m_did_push = true; - if (!m_class_name.empty()) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); - if (script_interp) { - m_implementation_sp = script_interp->CreateScriptedThreadPlan( - m_class_name.c_str(), m_args_data, m_error_str, - this->shared_from_this()); - } + if (m_interface) { + auto obj_or_err = m_interface->CreatePluginObject( + m_class_name, this->shared_from_this(), m_args_data); + if (!obj_or_err) { + m_error_str = llvm::toString(obj_or_err.takeError()); + SetPlanComplete(false); + } else + m_implementation_sp = *obj_or_err; } } @@ -77,14 +99,13 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) { bool should_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); - if (script_interp) { - bool script_error; - should_stop = script_interp->ScriptedThreadPlanShouldStop( - m_implementation_sp, event_ptr, script_error); - if (script_error) - SetPlanComplete(false); - } + auto should_stop_or_err = m_interface->ShouldStop(event_ptr); + if (!should_stop_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), should_stop_or_err.takeError(), + "Can't call ScriptedThreadPlan::ShouldStop."); + SetPlanComplete(false); + } else + should_stop = *should_stop_or_err; } return should_stop; } @@ -96,14 +117,13 @@ bool ThreadPlanPython::IsPlanStale() { bool is_stale = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); - if (script_interp) { - bool script_error; - is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, - script_error); - if (script_error) - SetPlanComplete(false); - } + auto is_stale_or_err = m_interface->IsStale(); + if (!is_stale_or_err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), is_stale_or_err.takeError(), + "Can't call ScriptedThreadPlan::IsStale."); + SetPlanComplete(false); + } else + is_stale = *is_stale_or_err; } return is_stale; } @@ -115,14 +135,14 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { bool explains_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); - if (script_interp) { - bool script_error; - explains_stop = script_interp->ScriptedThreadPlanExplainsStop( - m_implementation_sp, event_ptr, script_error); - if (script_error) - SetPlanComplete(false); - } + auto explains_stop_or_error = m_interface->ExplainsStop(event_ptr); + if (!explains_stop_or_error) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), + explains_stop_or_error.takeError(), + "Can't call ScriptedThreadPlan::ExplainsStop."); + SetPlanComplete(false); + } else + explains_stop = *explains_stop_or_error; } return explains_stop; } @@ -150,14 +170,8 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { LLDB_LOGF(log, "%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, m_class_name.c_str()); lldb::StateType run_state = eStateRunning; - if (m_implementation_sp) { - ScriptInterpreter *script_interp = GetScriptInterpreter(); - if (script_interp) { - bool script_error; - run_state = script_interp->ScriptedThreadPlanGetRunState( - m_implementation_sp, script_error); - } - } + if (m_implementation_sp) + run_state = m_interface->GetRunState(); return run_state; } @@ -168,12 +182,16 @@ void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { if (m_implementation_sp) { ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { - bool script_error; - bool added_desc = script_interp->ScriptedThreadPlanGetStopDescription( - m_implementation_sp, s, script_error); - if (script_error || !added_desc) + lldb::StreamSP stream = std::make_shared<lldb_private::StreamString>(); + llvm::Error err = m_interface->GetStopDescription(stream); + if (err) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(err), + "Can't call ScriptedThreadPlan::GetStopDescription."); s->Printf("Python thread plan implemented by class %s.", m_class_name.c_str()); + } else + s->PutCString( + reinterpret_cast<StreamString *>(stream.get())->GetData()); } return; } diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp index 84f282f1de52..abe4d34bd32c 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -220,8 +220,9 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0); sc = frame_sp->GetSymbolContext(eSymbolContextEverything); if (sc.line_entry.IsValid()) { - if (*sc.line_entry.original_file_sp != - *m_addr_context.line_entry.original_file_sp && + if (!sc.line_entry.original_file_sp->Equal( + *m_addr_context.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet) && sc.comp_unit == m_addr_context.comp_unit && sc.function == m_addr_context.function) { // Okay, find the next occurrence of this file in the line table: @@ -244,8 +245,9 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { LineEntry prev_line_entry; if (line_table->GetLineEntryAtIndex(entry_idx - 1, prev_line_entry) && - *prev_line_entry.original_file_sp == - *line_entry.original_file_sp) { + prev_line_entry.original_file_sp->Equal( + *line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet)) { SymbolContext prev_sc; Address prev_address = prev_line_entry.range.GetBaseAddress(); @@ -279,8 +281,9 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { if (next_line_function != m_addr_context.function) break; - if (*next_line_entry.original_file_sp == - *m_addr_context.line_entry.original_file_sp) { + if (next_line_entry.original_file_sp->Equal( + *m_addr_context.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet)) { const bool abort_other_plans = false; const RunMode stop_other_threads = RunMode::eAllThreads; lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0) @@ -355,7 +358,7 @@ bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { return_value = NextRangeBreakpointExplainsStop(stop_info_sp); } else { if (log) - log->PutCString("ThreadPlanStepInRange got asked if it explains the " + log->PutCString("ThreadPlanStepOverRange got asked if it explains the " "stop for some reason other than step."); return_value = false; } diff --git a/contrib/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp b/contrib/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp index 998e76cb65d1..801856bd5419 100644 --- a/contrib/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/contrib/llvm-project/lldb/source/Target/ThreadPlanStepRange.cpp @@ -120,8 +120,9 @@ bool ThreadPlanStepRange::InRange() { frame->GetSymbolContext(eSymbolContextEverything)); if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) { - if (*m_addr_context.line_entry.original_file_sp == - *new_context.line_entry.original_file_sp) { + if (m_addr_context.line_entry.original_file_sp->Equal( + *new_context.line_entry.original_file_sp, + SupportFile::eEqualFileSpecAndChecksumIfSet)) { if (m_addr_context.line_entry.line == new_context.line_entry.line) { m_addr_context = new_context; const bool include_inlined_functions = diff --git a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp index e92419e70b32..4ef8efc1a676 100644 --- a/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp +++ b/contrib/llvm-project/lldb/source/Target/TraceDumper.cpp @@ -57,7 +57,7 @@ static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) { return false; if (a.column != b.column) return false; - return a.file == b.file; + return a.GetFile() == b.GetFile(); } /// Compare the symbol contexts of the provided \a SymbolInfo @@ -396,7 +396,7 @@ public: m_j.attribute( "source", ToOptionalString( - item.symbol_info->sc.line_entry.file.GetPath().c_str())); + item.symbol_info->sc.line_entry.GetFile().GetPath().c_str())); m_j.attribute("line", item.symbol_info->sc.line_entry.line); m_j.attribute("column", item.symbol_info->sc.line_entry.column); } diff --git a/contrib/llvm-project/lldb/source/Target/UnwindLLDB.cpp b/contrib/llvm-project/lldb/source/Target/UnwindLLDB.cpp index 1d8bf2f88ae6..f43e940492b0 100644 --- a/contrib/llvm-project/lldb/source/Target/UnwindLLDB.cpp +++ b/contrib/llvm-project/lldb/source/Target/UnwindLLDB.cpp @@ -261,7 +261,12 @@ UnwindLLDB::CursorSP UnwindLLDB::GetOneMoreFrame(ABI *abi) { cur_idx < 100 ? cur_idx : 100, "", cur_idx); return nullptr; } - if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc)) { + + // Invalid code addresses should not appear on the stack *unless* we're + // directly below a trap handler frame (in this case, the invalid address is + // likely the cause of the trap). + if (abi && !abi->CodeAddressIsValid(cursor_sp->start_pc) && + !prev_frame->reg_ctx_lldb_sp->IsTrapHandlerFrame()) { // If the RegisterContextUnwind has a fallback UnwindPlan, it will switch to // that and return true. Subsequent calls to TryFallbackUnwindPlan() will // return false. diff --git a/contrib/llvm-project/lldb/source/Target/VerboseTrapFrameRecognizer.cpp b/contrib/llvm-project/lldb/source/Target/VerboseTrapFrameRecognizer.cpp new file mode 100644 index 000000000000..fe72c8aec570 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Target/VerboseTrapFrameRecognizer.cpp @@ -0,0 +1,122 @@ +#include "lldb/Target/VerboseTrapFrameRecognizer.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrameRecognizer.h" +#include "lldb/Target/Target.h" + +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "clang/CodeGen/ModuleBuilder.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +VerboseTrapRecognizedStackFrame::VerboseTrapRecognizedStackFrame( + StackFrameSP most_relevant_frame_sp, std::string stop_desc) + : m_most_relevant_frame(most_relevant_frame_sp) { + m_stop_desc = std::move(stop_desc); +} + +lldb::RecognizedStackFrameSP +VerboseTrapFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { + if (frame_sp->GetFrameIndex()) + return {}; + + ThreadSP thread_sp = frame_sp->GetThread(); + ProcessSP process_sp = thread_sp->GetProcess(); + + StackFrameSP most_relevant_frame_sp = thread_sp->GetStackFrameAtIndex(1); + + if (!most_relevant_frame_sp) { + Log *log = GetLog(LLDBLog::Unwind); + LLDB_LOG( + log, + "Failed to find most relevant frame: Hit unwinding bound (1 frame)!"); + return {}; + } + + SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + + if (!sc.block) + return {}; + + // The runtime error is set as the function name in the inlined function info + // of frame #0 by the compiler + const InlineFunctionInfo *inline_info = nullptr; + Block *inline_block = sc.block->GetContainingInlinedBlock(); + + if (!inline_block) + return {}; + + inline_info = sc.block->GetInlinedFunctionInfo(); + + if (!inline_info) + return {}; + + auto func_name = inline_info->GetName().GetStringRef(); + if (func_name.empty()) + return {}; + + static auto trap_regex = + llvm::Regex(llvm::formatv("^{0}\\$(.*)\\$(.*)$", ClangTrapPrefix).str()); + SmallVector<llvm::StringRef, 3> matches; + std::string regex_err_msg; + if (!trap_regex.match(func_name, &matches, ®ex_err_msg)) { + LLDB_LOGF(GetLog(LLDBLog::Unwind), + "Failed to parse match trap regex for '%s': %s", func_name.data(), + regex_err_msg.c_str()); + + return {}; + } + + // For `__clang_trap_msg$category$message$` we expect 3 matches: + // 1. entire string + // 2. category + // 3. message + if (matches.size() != 3) { + LLDB_LOGF(GetLog(LLDBLog::Unwind), + "Unexpected function name format. Expected '<trap prefix>$<trap " + "category>$<trap message>'$ but got: '%s'.", + func_name.data()); + + return {}; + } + + auto category = matches[1]; + auto message = matches[2]; + + std::string stop_reason = + category.empty() ? "<empty category>" : category.str(); + if (!message.empty()) { + stop_reason += ": "; + stop_reason += message.str(); + } + + return std::make_shared<VerboseTrapRecognizedStackFrame>( + most_relevant_frame_sp, std::move(stop_reason)); +} + +lldb::StackFrameSP VerboseTrapRecognizedStackFrame::GetMostRelevantFrame() { + return m_most_relevant_frame; +} + +namespace lldb_private { + +void RegisterVerboseTrapFrameRecognizer(Process &process) { + RegularExpressionSP module_regex_sp = nullptr; + auto symbol_regex_sp = std::make_shared<RegularExpression>( + llvm::formatv("^{0}", ClangTrapPrefix).str()); + + StackFrameRecognizerSP srf_recognizer_sp = + std::make_shared<VerboseTrapFrameRecognizer>(); + + process.GetTarget().GetFrameRecognizerManager().AddRecognizer( + srf_recognizer_sp, module_regex_sp, symbol_regex_sp, false); +} + +} // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp b/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp index c6e25f608da7..4c98addc1f07 100644 --- a/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp +++ b/contrib/llvm-project/lldb/source/Utility/AddressableBits.cpp @@ -7,9 +7,10 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/AddressableBits.h" -#include "lldb/Target/Process.h" #include "lldb/lldb-types.h" +#include <cassert> + using namespace lldb; using namespace lldb_private; @@ -28,24 +29,23 @@ void AddressableBits::SetLowmemAddressableBits( m_low_memory_addr_bits = lowmem_addressing_bits; } +uint32_t AddressableBits::GetLowmemAddressableBits() const { + return m_low_memory_addr_bits; +} + void AddressableBits::SetHighmemAddressableBits( uint32_t highmem_addressing_bits) { m_high_memory_addr_bits = highmem_addressing_bits; } -void AddressableBits::SetProcessMasks(Process &process) { - if (m_low_memory_addr_bits == 0 && m_high_memory_addr_bits == 0) - return; - - if (m_low_memory_addr_bits != 0) { - addr_t low_addr_mask = ~((1ULL << m_low_memory_addr_bits) - 1); - process.SetCodeAddressMask(low_addr_mask); - process.SetDataAddressMask(low_addr_mask); - } - - if (m_high_memory_addr_bits != 0) { - addr_t hi_addr_mask = ~((1ULL << m_high_memory_addr_bits) - 1); - process.SetHighmemCodeAddressMask(hi_addr_mask); - process.SetHighmemDataAddressMask(hi_addr_mask); - } +uint32_t AddressableBits::GetHighmemAddressableBits() const { + return m_high_memory_addr_bits; +} + +addr_t AddressableBits::AddressableBitToMask(uint32_t addressable_bits) { + assert(addressable_bits <= sizeof(addr_t) * 8); + if (addressable_bits == 64) + return 0; // all bits used for addressing + else + return ~((1ULL << addressable_bits) - 1); } diff --git a/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp b/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp index fb0e985a0d56..07ef435ef451 100644 --- a/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp +++ b/contrib/llvm-project/lldb/source/Utility/ArchSpec.cpp @@ -1421,23 +1421,6 @@ bool ArchSpec::IsFullySpecifiedTriple() const { return true; } -void ArchSpec::PiecewiseTripleCompare( - const ArchSpec &other, bool &arch_different, bool &vendor_different, - bool &os_different, bool &os_version_different, bool &env_different) const { - const llvm::Triple &me(GetTriple()); - const llvm::Triple &them(other.GetTriple()); - - arch_different = (me.getArch() != them.getArch()); - - vendor_different = (me.getVendor() != them.getVendor()); - - os_different = (me.getOS() != them.getOS()); - - os_version_different = (me.getOSMajorVersion() != them.getOSMajorVersion()); - - env_different = (me.getEnvironment() != them.getEnvironment()); -} - bool ArchSpec::IsAlwaysThumbInstructions() const { std::string Status; if (GetTriple().getArch() == llvm::Triple::arm || diff --git a/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp b/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp index 33cd49963e7c..c6b2606afe0c 100644 --- a/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Broadcaster.cpp @@ -87,7 +87,7 @@ bool Broadcaster::BroadcasterImpl::HasListeners(uint32_t event_mask) { } void Broadcaster::BroadcasterImpl::Clear() { - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); // Make sure the listener forgets about this broadcaster. We do this in the // broadcaster in case the broadcaster object initiates the removal. @@ -137,7 +137,7 @@ Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp, if (!listener_sp) return 0; - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); // See if we already have this listener, and if so, update its mask @@ -171,7 +171,7 @@ Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp, } bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) { - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back()) return true; @@ -195,14 +195,14 @@ bool Broadcaster::BroadcasterImpl::RemoveListener( return true; } - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); for (auto it = m_listeners.begin(); it != m_listeners.end();) { lldb::ListenerSP curr_listener_sp(it->first.lock()); if (!curr_listener_sp) { // The weak pointer for this listener didn't resolve, lets' prune it // as we go. - m_listeners.erase(it); + it = m_listeners.erase(it); continue; } @@ -213,8 +213,8 @@ bool Broadcaster::BroadcasterImpl::RemoveListener( if (!it->second) m_listeners.erase(it); return true; - } else - it++; + } + it++; } return false; } @@ -243,7 +243,7 @@ void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp, const uint32_t event_type = event_sp->GetType(); - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); ListenerSP hijacking_listener_sp; @@ -311,9 +311,8 @@ void Broadcaster::BroadcasterImpl::BroadcastEvent( PrivateBroadcastEvent(event_sp, false); } -void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique( - uint32_t event_type, EventData *event_data) { - auto event_sp = std::make_shared<Event>(event_type, event_data); +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(uint32_t event_type) { + auto event_sp = std::make_shared<Event>(event_type, /*data = */ nullptr); PrivateBroadcastEvent(event_sp, true); } @@ -328,7 +327,7 @@ void Broadcaster::BroadcasterImpl::SetPrimaryListener(lldb::ListenerSP bool Broadcaster::BroadcasterImpl::HijackBroadcaster( const lldb::ListenerSP &listener_sp, uint32_t event_mask) { - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); Log *log = GetLog(LLDBLog::Events); LLDB_LOG( @@ -342,7 +341,7 @@ bool Broadcaster::BroadcasterImpl::HijackBroadcaster( } bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) { - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); if (!m_hijacking_listeners.empty()) return (event_mask & m_hijacking_masks.back()) != 0; @@ -357,7 +356,7 @@ const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() { } void Broadcaster::BroadcasterImpl::RestoreBroadcaster() { - std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + std::lock_guard<std::mutex> guard(m_listeners_mutex); if (!m_hijacking_listeners.empty()) { ListenerSP listener_sp = m_hijacking_listeners.back(); @@ -374,8 +373,8 @@ void Broadcaster::BroadcasterImpl::RestoreBroadcaster() { m_hijacking_masks.pop_back(); } -ConstString &Broadcaster::GetBroadcasterClass() const { - static ConstString class_name("lldb.anonymous"); +llvm::StringRef Broadcaster::GetBroadcasterClass() const { + static constexpr llvm::StringLiteral class_name("lldb.anonymous"); return class_name; } @@ -392,10 +391,8 @@ lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() { return lldb::BroadcasterManagerSP(new BroadcasterManager()); } -uint32_t BroadcasterManager::RegisterListenerForEvents( +uint32_t BroadcasterManager::RegisterListenerForEventsNoLock( const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); - collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); uint32_t available_bits = event_spec.GetEventBits(); @@ -420,9 +417,8 @@ uint32_t BroadcasterManager::RegisterListenerForEvents( return available_bits; } -bool BroadcasterManager::UnregisterListenerForEvents( +bool BroadcasterManager::UnregisterListenerForEventsNoLock( const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); bool removed_some = false; if (m_listeners.erase(listener_sp) == 0) @@ -465,7 +461,7 @@ bool BroadcasterManager::UnregisterListenerForEvents( ListenerSP BroadcasterManager::GetListenerForEventSpec( const BroadcastEventSpec &event_spec) const { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + std::lock_guard<std::mutex> guard(m_manager_mutex); auto event_spec_matches = [&event_spec](const event_listener_key &input) -> bool { @@ -480,7 +476,7 @@ ListenerSP BroadcasterManager::GetListenerForEventSpec( } void BroadcasterManager::RemoveListener(Listener *listener) { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + std::lock_guard<std::mutex> guard(m_manager_mutex); auto listeners_predicate = [&listener](const lldb::ListenerSP &input) -> bool { return input.get() == listener; @@ -505,7 +501,7 @@ void BroadcasterManager::RemoveListener(Listener *listener) { } void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + std::lock_guard<std::mutex> guard(m_manager_mutex); auto listener_matches = [&listener_sp](const event_listener_key &input) -> bool { @@ -527,7 +523,7 @@ void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) { void BroadcasterManager::SignUpListenersForBroadcaster( Broadcaster &broadcaster) { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + std::lock_guard<std::mutex> guard(m_manager_mutex); collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); @@ -545,7 +541,7 @@ void BroadcasterManager::SignUpListenersForBroadcaster( } void BroadcasterManager::Clear() { - std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + std::lock_guard<std::mutex> guard(m_manager_mutex); for (auto &listener : m_listeners) listener->BroadcasterManagerWillDestruct(this->shared_from_this()); diff --git a/contrib/llvm-project/lldb/source/Utility/ConstString.cpp b/contrib/llvm-project/lldb/source/Utility/ConstString.cpp index 4535771adfb7..ea897dc611cc 100644 --- a/contrib/llvm-project/lldb/source/Utility/ConstString.cpp +++ b/contrib/llvm-project/lldb/source/Utility/ConstString.cpp @@ -77,10 +77,10 @@ public: return 0; } - StringPoolValueType GetMangledCounterpart(const char *ccstr) const { + StringPoolValueType GetMangledCounterpart(const char *ccstr) { if (ccstr != nullptr) { - const uint8_t h = hash(llvm::StringRef(ccstr)); - llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); + const PoolEntry &pool = selectPool(llvm::StringRef(ccstr)); + llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex); return GetStringMapEntryFromKeyData(ccstr).getValue(); } return nullptr; @@ -100,19 +100,20 @@ public: const char *GetConstCStringWithStringRef(llvm::StringRef string_ref) { if (string_ref.data()) { - const uint8_t h = hash(string_ref); + const uint32_t string_hash = StringPool::hash(string_ref); + PoolEntry &pool = selectPool(string_hash); { - llvm::sys::SmartScopedReader<false> rlock(m_string_pools[h].m_mutex); - auto it = m_string_pools[h].m_string_map.find(string_ref); - if (it != m_string_pools[h].m_string_map.end()) + llvm::sys::SmartScopedReader<false> rlock(pool.m_mutex); + auto it = pool.m_string_map.find(string_ref, string_hash); + if (it != pool.m_string_map.end()) return it->getKeyData(); } - llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex); StringPoolEntryType &entry = - *m_string_pools[h] - .m_string_map.insert(std::make_pair(string_ref, nullptr)) + *pool.m_string_map + .insert(std::make_pair(string_ref, nullptr), string_hash) .first; return entry.getKeyData(); } @@ -125,12 +126,14 @@ public: const char *demangled_ccstr = nullptr; { - const uint8_t h = hash(demangled); - llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + const uint32_t demangled_hash = StringPool::hash(demangled); + PoolEntry &pool = selectPool(demangled_hash); + llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex); // Make or update string pool entry with the mangled counterpart - StringPool &map = m_string_pools[h].m_string_map; - StringPoolEntryType &entry = *map.try_emplace(demangled).first; + StringPool &map = pool.m_string_map; + StringPoolEntryType &entry = + *map.try_emplace_with_hash(demangled, demangled_hash).first; entry.second = mangled_ccstr; @@ -141,8 +144,8 @@ public: { // Now assign the demangled const string as the counterpart of the // mangled const string... - const uint8_t h = hash(llvm::StringRef(mangled_ccstr)); - llvm::sys::SmartScopedWriter<false> wlock(m_string_pools[h].m_mutex); + PoolEntry &pool = selectPool(llvm::StringRef(mangled_ccstr)); + llvm::sys::SmartScopedWriter<false> wlock(pool.m_mutex); GetStringMapEntryFromKeyData(mangled_ccstr).setValue(demangled_ccstr); } @@ -171,17 +174,20 @@ public: } protected: - uint8_t hash(llvm::StringRef s) const { - uint32_t h = llvm::djbHash(s); - return ((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff; - } - struct PoolEntry { mutable llvm::sys::SmartRWMutex<false> m_mutex; StringPool m_string_map; }; std::array<PoolEntry, 256> m_string_pools; + + PoolEntry &selectPool(const llvm::StringRef &s) { + return selectPool(StringPool::hash(s)); + } + + PoolEntry &selectPool(uint32_t h) { + return m_string_pools[((h >> 24) ^ (h >> 16) ^ (h >> 8) ^ h) & 0xff]; + } }; // Frameworks and dylibs aren't supposed to have global C++ initializers so we @@ -197,7 +203,7 @@ static Pool &StringPool() { static Pool *g_string_pool = nullptr; llvm::call_once(g_pool_initialization_flag, - []() { g_string_pool = new Pool(); }); + []() { g_string_pool = new Pool(); }); return *g_string_pool; } diff --git a/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp b/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp new file mode 100644 index 000000000000..aea5cb5f47c1 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Utility/ErrorMessages.cpp @@ -0,0 +1,40 @@ +//===-- ErrorMessages.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/ErrorMessages.h" +#include "llvm/Support/ErrorHandling.h" + +namespace lldb_private { + +std::string toString(lldb::ExpressionResults e) { + switch (e) { + case lldb::eExpressionSetupError: + return "expression setup error"; + case lldb::eExpressionParseError: + return "expression parse error"; + case lldb::eExpressionResultUnavailable: + return "expression error"; + case lldb::eExpressionCompleted: + return "expression completed successfully"; + case lldb::eExpressionDiscarded: + return "expression discarded"; + case lldb::eExpressionInterrupted: + return "expression interrupted"; + case lldb::eExpressionHitBreakpoint: + return "expression hit breakpoint"; + case lldb::eExpressionTimedOut: + return "expression timed out"; + case lldb::eExpressionStoppedForDebug: + return "expression stop at entry point for debugging"; + case lldb::eExpressionThreadVanished: + return "expression thread vanished"; + } + llvm_unreachable("unhandled enumerator"); +} + +} // namespace lldb_private diff --git a/contrib/llvm-project/lldb/source/Utility/Event.cpp b/contrib/llvm-project/lldb/source/Utility/Event.cpp index cac118182c75..5f431c0a6dd8 100644 --- a/contrib/llvm-project/lldb/source/Utility/Event.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Event.cpp @@ -83,14 +83,20 @@ void Event::Dump(Stream *s) const { void Event::DoOnRemoval() { std::lock_guard<std::mutex> guard(m_listeners_mutex); - if (m_data_sp) - m_data_sp->DoOnRemoval(this); + if (!m_data_sp) + return; + + m_data_sp->DoOnRemoval(this); + // Now that the event has been handled by the primary event Listener, forward // it to the other Listeners. + EventSP me_sp = shared_from_this(); - for (auto listener_sp : m_pending_listeners) - listener_sp->AddEvent(me_sp); - m_pending_listeners.clear(); + if (m_data_sp->ForwardEventToPendingListeners(this)) { + for (auto listener_sp : m_pending_listeners) + listener_sp->AddEvent(me_sp); + m_pending_listeners.clear(); + } } #pragma mark - @@ -111,17 +117,7 @@ void EventData::Dump(Stream *s) const { s->PutCString("Generic Event Data"); } EventDataBytes::EventDataBytes() : m_bytes() {} -EventDataBytes::EventDataBytes(const char *cstr) : m_bytes() { - SetBytesFromCString(cstr); -} - -EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes() { - SetBytes(str.data(), str.size()); -} - -EventDataBytes::EventDataBytes(const void *src, size_t src_len) : m_bytes() { - SetBytes(src, src_len); -} +EventDataBytes::EventDataBytes(llvm::StringRef str) : m_bytes(str.str()) {} EventDataBytes::~EventDataBytes() = default; @@ -147,20 +143,6 @@ const void *EventDataBytes::GetBytes() const { size_t EventDataBytes::GetByteSize() const { return m_bytes.size(); } -void EventDataBytes::SetBytes(const void *src, size_t src_len) { - if (src != nullptr && src_len > 0) - m_bytes.assign(static_cast<const char *>(src), src_len); - else - m_bytes.clear(); -} - -void EventDataBytes::SetBytesFromCString(const char *cstr) { - if (cstr != nullptr && cstr[0]) - m_bytes.assign(cstr); - else - m_bytes.clear(); -} - const void *EventDataBytes::GetBytesFromEvent(const Event *event_ptr) { const EventDataBytes *e = GetEventDataFromEvent(event_ptr); if (e != nullptr) @@ -186,10 +168,6 @@ EventDataBytes::GetEventDataFromEvent(const Event *event_ptr) { return nullptr; } -void EventDataBytes::SwapBytes(std::string &new_bytes) { - m_bytes.swap(new_bytes); -} - llvm::StringRef EventDataReceipt::GetFlavorString() { return "Process::ProcessEventData"; } diff --git a/contrib/llvm-project/lldb/source/Utility/Listener.cpp b/contrib/llvm-project/lldb/source/Utility/Listener.cpp index 6a74c530ad25..1efaad392502 100644 --- a/contrib/llvm-project/lldb/source/Utility/Listener.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Listener.cpp @@ -18,28 +18,21 @@ using namespace lldb; using namespace lldb_private; -Listener::Listener(const char *name) - : m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(), - m_events_mutex(), m_is_shadow() { - Log *log = GetLog(LLDBLog::Object); - if (log != nullptr) - LLDB_LOGF(log, "%p Listener::Listener('%s')", static_cast<void *>(this), - m_name.c_str()); +Listener::Listener(const char *name) : m_name(name) { + LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::Listener('%s')", + static_cast<void *>(this), m_name.c_str()); } Listener::~Listener() { - Log *log = GetLog(LLDBLog::Object); - - Clear(); + // Don't call Clear() from here as that can cause races. See #96750. - LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast<void *>(this), - __FUNCTION__, m_name.c_str()); + LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::%s('%s')", + static_cast<void *>(this), __FUNCTION__, m_name.c_str()); } void Listener::Clear() { Log *log = GetLog(LLDBLog::Object); - std::lock_guard<std::recursive_mutex> broadcasters_guard( - m_broadcasters_mutex); + std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); broadcaster_collection::iterator pos, end = m_broadcasters.end(); for (pos = m_broadcasters.begin(); pos != end; ++pos) { Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock()); @@ -68,8 +61,7 @@ uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, // Scope for "locker" // Tell the broadcaster to add this object as a listener { - std::lock_guard<std::recursive_mutex> broadcasters_guard( - m_broadcasters_mutex); + std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); m_broadcasters.insert( std::make_pair(impl_wp, BroadcasterInfo(event_mask))); @@ -99,8 +91,7 @@ uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, // Scope for "locker" // Tell the broadcaster to add this object as a listener { - std::lock_guard<std::recursive_mutex> broadcasters_guard( - m_broadcasters_mutex); + std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); m_broadcasters.insert(std::make_pair( impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data))); @@ -131,8 +122,7 @@ bool Listener::StopListeningForEvents(Broadcaster *broadcaster, if (broadcaster) { // Scope for "locker" { - std::lock_guard<std::recursive_mutex> broadcasters_guard( - m_broadcasters_mutex); + std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); } // Remove the broadcaster from our set of broadcasters @@ -147,8 +137,7 @@ bool Listener::StopListeningForEvents(Broadcaster *broadcaster, void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) { // Scope for "broadcasters_locker" { - std::lock_guard<std::recursive_mutex> broadcasters_guard( - m_broadcasters_mutex); + std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); } @@ -322,7 +311,7 @@ bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) { size_t Listener::HandleBroadcastEvent(EventSP &event_sp) { size_t num_handled = 0; - std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + std::lock_guard<std::mutex> guard(m_broadcasters_mutex); Broadcaster *broadcaster = event_sp->GetBroadcaster(); if (!broadcaster) return 0; @@ -356,11 +345,10 @@ Listener::StartListeningForEventSpec(const BroadcasterManagerSP &manager_sp, }; // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to // avoid violating the lock hierarchy (manager before broadcasters). - std::lock_guard<std::recursive_mutex> manager_guard( - manager_sp->m_manager_mutex); - std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); + std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex); + std::lock_guard<std::mutex> guard(m_broadcasters_mutex); - uint32_t bits_acquired = manager_sp->RegisterListenerForEvents( + uint32_t bits_acquired = manager_sp->RegisterListenerForEventsNoLock( this->shared_from_this(), event_spec); if (bits_acquired) { BroadcasterManagerWP manager_wp(manager_sp); @@ -377,9 +365,12 @@ bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp, if (!manager_sp) return false; - std::lock_guard<std::recursive_mutex> guard(m_broadcasters_mutex); - return manager_sp->UnregisterListenerForEvents(this->shared_from_this(), - event_spec); + // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to + // avoid violating the lock hierarchy (manager before broadcasters). + std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex); + std::lock_guard<std::mutex> guard(m_broadcasters_mutex); + return manager_sp->UnregisterListenerForEventsNoLock(this->shared_from_this(), + event_spec); } ListenerSP Listener::MakeListener(const char *name) { diff --git a/contrib/llvm-project/lldb/source/Utility/Log.cpp b/contrib/llvm-project/lldb/source/Utility/Log.cpp index 3a45a0285d3e..6713a5bd7582 100644 --- a/contrib/llvm-project/lldb/source/Utility/Log.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Log.cpp @@ -39,6 +39,7 @@ char LogHandler::ID; char StreamLogHandler::ID; char CallbackLogHandler::ID; char RotatingLogHandler::ID; +char TeeLogHandler::ID; llvm::ManagedStatic<Log::ChannelMap> Log::g_channel_map; @@ -438,3 +439,16 @@ void RotatingLogHandler::Dump(llvm::raw_ostream &stream) const { } stream.flush(); } + +TeeLogHandler::TeeLogHandler(std::shared_ptr<LogHandler> first_log_handler, + std::shared_ptr<LogHandler> second_log_handler) + : m_first_log_handler(first_log_handler), + m_second_log_handler(second_log_handler) { + assert(m_first_log_handler && "first log handler must be valid"); + assert(m_second_log_handler && "second log handler must be valid"); +} + +void TeeLogHandler::Emit(llvm::StringRef message) { + m_first_log_handler->Emit(message); + m_second_log_handler->Emit(message); +} diff --git a/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp b/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp index 6b2a7114dfb4..845b337e246f 100644 --- a/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp +++ b/contrib/llvm-project/lldb/source/Utility/ProcessInfo.cpp @@ -121,8 +121,8 @@ void ProcessInstanceInfo::Dump(Stream &s, UserIDResolver &resolver) const { if (m_pid != LLDB_INVALID_PROCESS_ID) s.Printf(" pid = %" PRIu64 "\n", m_pid); - if (m_parent_pid != LLDB_INVALID_PROCESS_ID) - s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); + if (ParentProcessIDIsValid()) + s.Printf(" parent = %" PRIu64 "\n", GetParentProcessID()); if (m_executable) { s.Printf(" name = %s\n", m_executable.GetFilename().GetCString()); @@ -193,7 +193,8 @@ void ProcessInstanceInfo::DumpTableHeader(Stream &s, bool show_args, void ProcessInstanceInfo::DumpAsTableRow(Stream &s, UserIDResolver &resolver, bool show_args, bool verbose) const { if (m_pid != LLDB_INVALID_PROCESS_ID) { - s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); + s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, + (ParentProcessIDIsValid()) ? GetParentProcessID() : 0); StreamString arch_strm; if (m_arch.IsValid()) diff --git a/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp b/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp index fa92ba8a8f92..cbf840258302 100644 --- a/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp +++ b/contrib/llvm-project/lldb/source/Utility/RegisterValue.cpp @@ -199,7 +199,7 @@ Status RegisterValue::SetValueFromData(const RegisterInfo ®_info, else if (reg_info.byte_size <= 16) { uint64_t data1 = src.GetU64(&src_offset); uint64_t data2 = src.GetU64(&src_offset); - if (src.GetByteSize() == eByteOrderBig) { + if (src.GetByteOrder() == eByteOrderBig) { int128.x[0] = data1; int128.x[1] = data2; } else { diff --git a/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp b/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp index 20bebbfe15f2..026793462221 100644 --- a/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp +++ b/contrib/llvm-project/lldb/source/Utility/RegularExpression.cpp @@ -12,10 +12,11 @@ using namespace lldb_private; -RegularExpression::RegularExpression(llvm::StringRef str) +RegularExpression::RegularExpression(llvm::StringRef str, + llvm::Regex::RegexFlags flags) : m_regex_text(std::string(str)), // m_regex does not reference str anymore after it is constructed. - m_regex(llvm::Regex(str)) {} + m_regex(llvm::Regex(str, flags)) {} RegularExpression::RegularExpression(const RegularExpression &rhs) : RegularExpression(rhs.GetText()) {} diff --git a/contrib/llvm-project/lldb/source/Utility/Scalar.cpp b/contrib/llvm-project/lldb/source/Utility/Scalar.cpp index 5ad68065bce1..c680101aa9ef 100644 --- a/contrib/llvm-project/lldb/source/Utility/Scalar.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Scalar.cpp @@ -134,9 +134,9 @@ size_t Scalar::GetByteSize() const { case e_void: break; case e_int: - return (m_integer.getBitWidth() / 8); + return (m_integer.getBitWidth() + 7) / 8; case e_float: - return m_float.bitcastToAPInt().getBitWidth() / 8; + return (m_float.bitcastToAPInt().getBitWidth() + 7) / 8; } return 0; } @@ -753,9 +753,7 @@ bool Scalar::SignExtend(uint32_t sign_bit_pos) { return false; case Scalar::e_int: - if (max_bit_pos == sign_bit_pos) - return true; - else if (sign_bit_pos < (max_bit_pos - 1)) { + if (sign_bit_pos < (max_bit_pos - 1)) { llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); llvm::APInt bitwize_and = m_integer & sign_bit; if (bitwize_and.getBoolValue()) { @@ -813,6 +811,48 @@ bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { return false; } +llvm::APFloat Scalar::CreateAPFloatFromAPSInt(lldb::BasicType basic_type) { + switch (basic_type) { + case lldb::eBasicTypeFloat: + return llvm::APFloat( + m_integer.isSigned() + ? llvm::APIntOps::RoundSignedAPIntToFloat(m_integer) + : llvm::APIntOps::RoundAPIntToFloat(m_integer)); + case lldb::eBasicTypeDouble: + // No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: + return llvm::APFloat( + m_integer.isSigned() + ? llvm::APIntOps::RoundSignedAPIntToDouble(m_integer) + : llvm::APIntOps::RoundAPIntToDouble(m_integer)); + default: + const llvm::fltSemantics &sem = APFloat::IEEEsingle(); + return llvm::APFloat::getNaN(sem); + } +} + +llvm::APFloat Scalar::CreateAPFloatFromAPFloat(lldb::BasicType basic_type) { + switch (basic_type) { + case lldb::eBasicTypeFloat: { + bool loses_info; + m_float.convert(llvm::APFloat::IEEEsingle(), + llvm::APFloat::rmNearestTiesToEven, &loses_info); + return m_float; + } + case lldb::eBasicTypeDouble: + // No way to get more precision at the moment. + case lldb::eBasicTypeLongDouble: { + bool loses_info; + m_float.convert(llvm::APFloat::IEEEdouble(), + llvm::APFloat::rmNearestTiesToEven, &loses_info); + return m_float; + } + default: + const llvm::fltSemantics &sem = APFloat::IEEEsingle(); + return llvm::APFloat::getNaN(sem); + } +} + bool lldb_private::operator==(Scalar lhs, Scalar rhs) { // If either entry is void then we can just compare the types if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) diff --git a/contrib/llvm-project/lldb/source/Utility/Status.cpp b/contrib/llvm-project/lldb/source/Utility/Status.cpp index 3bd00bb20da2..18312e87f03e 100644 --- a/contrib/llvm-project/lldb/source/Utility/Status.cpp +++ b/contrib/llvm-project/lldb/source/Utility/Status.cpp @@ -92,8 +92,7 @@ llvm::Error Status::ToError() const { if (m_type == ErrorType::eErrorTypePOSIX) return llvm::errorCodeToError( std::error_code(m_code, std::generic_category())); - return llvm::make_error<llvm::StringError>(AsCString(), - llvm::inconvertibleErrorCode()); + return llvm::createStringError(AsCString()); } Status::~Status() = default; diff --git a/contrib/llvm-project/lldb/source/Utility/UriParser.cpp b/contrib/llvm-project/lldb/source/Utility/UriParser.cpp index 432b046d008b..1932e11acb4c 100644 --- a/contrib/llvm-project/lldb/source/Utility/UriParser.cpp +++ b/contrib/llvm-project/lldb/source/Utility/UriParser.cpp @@ -47,7 +47,7 @@ std::optional<URI> URI::Parse(llvm::StringRef uri) { ((path_pos != std::string::npos) ? path_pos : uri.size()) - host_pos); // Extract hostname - if (!host_port.empty() && host_port[0] == '[') { + if (host_port.starts_with('[')) { // hostname is enclosed with square brackets. pos = host_port.rfind(']'); if (pos == std::string::npos) diff --git a/contrib/llvm-project/lldb/tools/driver/Driver.cpp b/contrib/llvm-project/lldb/tools/driver/Driver.cpp index c63ff0ff597e..14371da64f2f 100644 --- a/contrib/llvm-project/lldb/tools/driver/Driver.cpp +++ b/contrib/llvm-project/lldb/tools/driver/Driver.cpp @@ -33,6 +33,7 @@ #include <bitset> #include <clocale> #include <csignal> +#include <future> #include <string> #include <thread> #include <utility> @@ -188,7 +189,6 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) { if (args.hasArg(OPT_no_use_colors)) { m_debugger.SetUseColor(false); WithColor::setAutoDetectFunction(disable_color); - m_option_data.m_debug_mode = true; } if (args.hasArg(OPT_version)) { @@ -455,16 +455,7 @@ int Driver::MainLoop() { // Process lldbinit files before handling any options from the command line. SBCommandReturnObject result; sb_interpreter.SourceInitFileInGlobalDirectory(result); - if (m_option_data.m_debug_mode) { - result.PutError(m_debugger.GetErrorFile()); - result.PutOutput(m_debugger.GetOutputFile()); - } - sb_interpreter.SourceInitFileInHomeDirectory(result, m_option_data.m_repl); - if (m_option_data.m_debug_mode) { - result.PutError(m_debugger.GetErrorFile()); - result.PutOutput(m_debugger.GetOutputFile()); - } // Source the local .lldbinit file if it exists and we're allowed to source. // Here we want to always print the return object because it contains the @@ -536,11 +527,6 @@ int Driver::MainLoop() { "or -s) are ignored in REPL mode.\n"; } - if (m_option_data.m_debug_mode) { - result.PutError(m_debugger.GetErrorFile()); - result.PutOutput(m_debugger.GetOutputFile()); - } - const bool handle_events = true; const bool spawn_thread = false; @@ -747,8 +733,14 @@ int main(int argc, char const *argv[]) { // Setup LLVM signal handlers and make sure we call llvm_shutdown() on // destruction. llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); +#if !defined(__APPLE__) llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL " and include the crash backtrace.\n"); +#else + llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL + " and include the crash report from " + "~/Library/Logs/DiagnosticReports/.\n"); +#endif // Parse arguments. LLDBOptTable T; @@ -816,6 +808,18 @@ int main(int argc, char const *argv[]) { } } - SBDebugger::Terminate(); + // When terminating the debugger we have to wait on all the background tasks + // to complete, which can take a while. Print a message when this takes longer + // than 1 second. + { + std::future<void> future = + std::async(std::launch::async, []() { SBDebugger::Terminate(); }); + + if (future.wait_for(std::chrono::seconds(1)) == std::future_status::timeout) + fprintf(stderr, "Waiting for background tasks to complete...\n"); + + future.wait(); + } + return exit_code; } diff --git a/contrib/llvm-project/lldb/tools/driver/Driver.h b/contrib/llvm-project/lldb/tools/driver/Driver.h index d5779b3c2c91..83e0d8a41cfd 100644 --- a/contrib/llvm-project/lldb/tools/driver/Driver.h +++ b/contrib/llvm-project/lldb/tools/driver/Driver.h @@ -75,7 +75,6 @@ public: std::vector<InitialCmdEntry> m_after_file_commands; std::vector<InitialCmdEntry> m_after_crash_commands; - bool m_debug_mode = false; bool m_source_quietly = false; bool m_print_version = false; bool m_print_python_path = false; diff --git a/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp b/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp index 38c00e83e7b0..563284730bc7 100644 --- a/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp +++ b/contrib/llvm-project/lldb/tools/lldb-server/lldb-gdbserver.cpp @@ -235,7 +235,7 @@ void ConnectToRemote(MainLoop &mainloop, Status error = writeSocketIdToPipe(named_pipe_path, socket_id); if (error.Fail()) llvm::errs() << llvm::formatv( - "failed to write to the named peipe '{0}': {1}\n", + "failed to write to the named pipe '{0}': {1}\n", named_pipe_path, error.AsCString()); } // If we have an unnamed pipe to write the socket id back to, do diff --git a/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp b/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp index 3e126584eb25..7148a1d2a309 100644 --- a/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp +++ b/contrib/llvm-project/lldb/tools/lldb-server/lldb-platform.cpp @@ -282,17 +282,12 @@ int main_platform(int argc, char *argv[]) { } } - do { - GDBRemoteCommunicationServerPlatform platform( - acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); - - if (port_offset > 0) - platform.SetPortOffset(port_offset); - - if (!gdbserver_portmap.empty()) { - platform.SetPortMap(std::move(gdbserver_portmap)); - } + GDBRemoteCommunicationServerPlatform platform( + acceptor_up->GetSocketProtocol(), acceptor_up->GetSocketScheme()); + if (port_offset > 0) + platform.SetPortOffset(port_offset); + do { const bool children_inherit_accept_socket = true; Connection *conn = nullptr; error = acceptor_up->Accept(children_inherit_accept_socket, conn); @@ -301,13 +296,39 @@ int main_platform(int argc, char *argv[]) { exit(socket_error); } printf("Connection established.\n"); + if (g_server) { // Collect child zombie processes. #if !defined(_WIN32) - while (waitpid(-1, nullptr, WNOHANG) > 0) - ; + ::pid_t waitResult; + while ((waitResult = waitpid(-1, nullptr, WNOHANG)) > 0) { + // waitResult is the child pid + gdbserver_portmap.FreePortForProcess(waitResult); + } #endif - if (fork()) { + // TODO: Clean up portmap for Windows when children die + // See https://github.com/llvm/llvm-project/issues/90923 + + // After collecting zombie ports, get the next available + GDBRemoteCommunicationServerPlatform::PortMap portmap_for_child; + llvm::Expected<uint16_t> available_port = + gdbserver_portmap.GetNextAvailablePort(); + if (available_port) { + // GetNextAvailablePort() may return 0 if gdbserver_portmap is empty. + if (*available_port) + portmap_for_child.AllowPort(*available_port); + } else { + llvm::consumeError(available_port.takeError()); + fprintf(stderr, + "no available gdbserver port for connection - dropping...\n"); + delete conn; + continue; + } + platform.SetPortMap(std::move(portmap_for_child)); + + auto childPid = fork(); + if (childPid) { + gdbserver_portmap.AssociatePortWithProcess(*available_port, childPid); // Parent doesn't need a connection to the lldb client delete conn; @@ -323,13 +344,17 @@ int main_platform(int argc, char *argv[]) { // If not running as a server, this process will not accept // connections while a connection is active. acceptor_up.reset(); + + // When not running in server mode, use all available ports + platform.SetPortMap(std::move(gdbserver_portmap)); } + platform.SetConnection(std::unique_ptr<Connection>(conn)); if (platform.IsConnected()) { if (inferior_arguments.GetArgumentCount() > 0) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - std::optional<uint16_t> port = 0; + std::optional<uint16_t> port; std::string socket_name; Status error = platform.LaunchGDBServer(inferior_arguments, "", // hostname diff --git a/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGen.cpp b/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGen.cpp index abb6589f0ca6..bbd3f3d6c66c 100644 --- a/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGen.cpp +++ b/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGen.cpp @@ -12,6 +12,7 @@ #include "LLDBTableGenBackends.h" // Declares all backends. #include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/TableGen/Error.h" @@ -67,7 +68,6 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - llvm_shutdown_obj Y; return TableGenMain(argv[0], &LLDBTableGenMain); diff --git a/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGenBackends.h b/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGenBackends.h index 88ae0888c22d..b60c4705de3a 100644 --- a/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGenBackends.h +++ b/contrib/llvm-project/lldb/utils/TableGen/LLDBTableGenBackends.h @@ -32,6 +32,7 @@ namespace lldb_private { void EmitOptionDefs(RecordKeeper &RK, raw_ostream &OS); void EmitPropertyDefs(RecordKeeper &RK, raw_ostream &OS); void EmitPropertyEnumDefs(RecordKeeper &RK, raw_ostream &OS); +int EmitSBAPIDWARFEnum(int argc, char **argv); } // namespace lldb_private |