diff options
Diffstat (limited to 'lldb')
53 files changed, 804 insertions, 388 deletions
diff --git a/lldb/docs/use/tutorials/implementing-standalone-scripts.md b/lldb/docs/use/tutorials/implementing-standalone-scripts.md index 285d2d3..b1a3441 100644 --- a/lldb/docs/use/tutorials/implementing-standalone-scripts.md +++ b/lldb/docs/use/tutorials/implementing-standalone-scripts.md @@ -147,3 +147,20 @@ SBFunction: id = 0x0000002e, name = main, type = main a.out[0x714]: mov w0, #0x0 ; =0 a.out[0x718]: ret ``` + +### Troubleshooting + +You can use all the usual Python tools to debug scripts, and on top of that +you can enable LLDB's log channels. To do this in the script shown above, add +this line right after `debugger` has been assigned: + +```python +debugger.EnableLog("lldb", ["all"]) +``` + +`lldb` `all` enables a lot of different channels, so you will probably want +to enable only a few channels once you know what you are interested in. + +This API call is the equivalent of `log enable lldb all` when using LLDB +interactively. All channels available to `log enable` can be enabled using +`EnableLog` too.
\ No newline at end of file diff --git a/lldb/include/lldb/Core/SourceManager.h b/lldb/include/lldb/Core/SourceManager.h index 1244291..83dc747 100644 --- a/lldb/include/lldb/Core/SourceManager.h +++ b/lldb/include/lldb/Core/SourceManager.h @@ -109,6 +109,8 @@ public: private: void CommonInitializer(lldb::SupportFileSP support_file_sp, lldb::TargetSP target_sp); + void CommonInitializerImpl(lldb::SupportFileSP support_file_sp, + lldb::TargetSP target_sp); }; typedef std::shared_ptr<File> FileSP; diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index df8489a..869c507 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -144,7 +144,7 @@ public: bool IsDefined() const; - bool IsFloatingPointType(uint32_t &count, bool &is_complex) const; + bool IsFloatingPointType(bool &is_complex) const; bool IsFunctionType() const; @@ -400,7 +400,7 @@ public: /// Return the size of the type in bits. llvm::Expected<uint64_t> GetBitSize(ExecutionContextScope *exe_scope) const; - lldb::Encoding GetEncoding(uint64_t &count) const; + lldb::Encoding GetEncoding() const; lldb::Format GetFormat() const; diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index e657357..02b43e3 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -507,7 +507,7 @@ public: lldb::Format GetFormat(); - lldb::Encoding GetEncoding(uint64_t &count); + lldb::Encoding GetEncoding(); SymbolContextScope *GetSymbolContextScope() { return m_context; } const SymbolContextScope *GetSymbolContextScope() const { return m_context; } diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 0ec3a28..25b208a 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -163,7 +163,7 @@ public: virtual bool IsDefined(lldb::opaque_compiler_type_t type) = 0; virtual bool IsFloatingPointType(lldb::opaque_compiler_type_t type, - uint32_t &count, bool &is_complex) = 0; + bool &is_complex) = 0; virtual bool IsFunctionType(lldb::opaque_compiler_type_t type) = 0; @@ -317,8 +317,7 @@ public: GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) = 0; - virtual lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type, - uint64_t &count) = 0; + virtual lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type) = 0; virtual lldb::Format GetFormat(lldb::opaque_compiler_type_t type) = 0; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index c375df2..40f9c9b 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1346,6 +1346,13 @@ public: const lldb_private::RegisterFlags &flags, uint32_t byte_size); + /// Sends a breakpoint notification event. + void NotifyBreakpointChanged(Breakpoint &bp, + lldb::BreakpointEventType event_kind); + /// Sends a breakpoint notification event. + void NotifyBreakpointChanged(Breakpoint &bp, + const lldb::EventDataSP &breakpoint_data_sp); + llvm::Expected<lldb::DisassemblerSP> ReadInstructions(const Address &start_addr, uint32_t count, const char *flavor_string = nullptr); diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index 09939e2..28cae54 100644 --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -322,6 +322,17 @@ ifeq (,$(filter $(OS), Windows_NT Android Darwin)) LDFLAGS += -pthread endif endif + +# macOS forbids injecting the ASAN runtime into system processes when +# SIP is enabled. That includes the just-built libLTO that the +# just-built clang injects into the system linker. Since we don't +# test the compiler here, just use the system (non-asanified) LTO +# library to make ASAN tests work for most users, including the bots. +ifeq "$(OS)" "Darwin" +ifneq "$(ASAN_OPTIONS)" "" +LD_FLAGS += -Wl,-lto_library -Wl,$(shell dirname $(shell xcrun -find clang))/../lib/libLTO.dylib +endif +endif OBJECTS = EXE ?= a.out diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 8f36521..d892c01 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -10,8 +10,8 @@ import string import subprocess import signal import sys +import threading import warnings -import selectors import time from typing import ( Any, @@ -139,6 +139,35 @@ def dump_memory(base_addr, data, num_per_line, outfile): outfile.write("\n") +def read_packet( + f: IO[bytes], trace_file: Optional[IO[str]] = None +) -> Optional[ProtocolMessage]: + """Decode a JSON packet that starts with the content length and is + followed by the JSON bytes from a file 'f'. Returns None on EOF. + """ + line = f.readline().decode("utf-8") + if len(line) == 0: + return None # EOF. + + # Watch for line that starts with the prefix + prefix = "Content-Length: " + if line.startswith(prefix): + # Decode length of JSON bytes + length = int(line[len(prefix) :]) + # Skip empty line + separator = f.readline().decode() + if separator != "": + Exception("malformed DAP content header, unexpected line: " + separator) + # Read JSON bytes + json_str = f.read(length).decode() + if trace_file: + trace_file.write("from adapter:\n%s\n" % (json_str)) + # Decode the JSON bytes into a python dictionary + return json.loads(json_str) + + raise Exception("unexpected malformed message from lldb-dap: " + line) + + def packet_type_is(packet, packet_type): return "type" in packet and packet["type"] == packet_type @@ -170,8 +199,16 @@ class DebugCommunication(object): self.log_file = log_file self.send = send self.recv = recv - self.selector = selectors.DefaultSelector() - self.selector.register(recv, selectors.EVENT_READ) + + # Packets that have been received and processed but have not yet been + # requested by a test case. + self._pending_packets: List[Optional[ProtocolMessage]] = [] + # Received packets that have not yet been processed. + self._recv_packets: List[Optional[ProtocolMessage]] = [] + # Used as a mutex for _recv_packets and for notify when _recv_packets + # changes. + self._recv_condition = threading.Condition() + self._recv_thread = threading.Thread(target=self._read_packet_thread) # session state self.init_commands = init_commands @@ -197,6 +234,9 @@ class DebugCommunication(object): # keyed by breakpoint id self.resolved_breakpoints: dict[str, Breakpoint] = {} + # trigger enqueue thread + self._recv_thread.start() + @classmethod def encode_content(cls, s: str) -> bytes: return ("Content-Length: %u\r\n\r\n%s" % (len(s), s)).encode("utf-8") @@ -212,46 +252,17 @@ class DebugCommunication(object): f"seq mismatch in response {command['seq']} != {response['request_seq']}" ) - def _read_packet( - self, - timeout: float = DEFAULT_TIMEOUT, - ) -> Optional[ProtocolMessage]: - """Decode a JSON packet that starts with the content length and is - followed by the JSON bytes from self.recv. Returns None on EOF. - """ - - ready = self.selector.select(timeout) - if not ready: - warnings.warn( - "timeout occurred waiting for a packet, check if the test has a" - " negative assertion and see if it can be inverted.", - stacklevel=4, - ) - return None # timeout - - line = self.recv.readline().decode("utf-8") - if len(line) == 0: - return None # EOF. - - # Watch for line that starts with the prefix - prefix = "Content-Length: " - if line.startswith(prefix): - # Decode length of JSON bytes - length = int(line[len(prefix) :]) - # Skip empty line - separator = self.recv.readline().decode() - if separator != "": - Exception("malformed DAP content header, unexpected line: " + separator) - # Read JSON bytes - json_str = self.recv.read(length).decode() - if self.trace_file: - self.trace_file.write( - "%s from adapter:\n%s\n" % (time.time(), json_str) - ) - # Decode the JSON bytes into a python dictionary - return json.loads(json_str) - - raise Exception("unexpected malformed message from lldb-dap: " + line) + def _read_packet_thread(self): + try: + while True: + packet = read_packet(self.recv, trace_file=self.trace_file) + # `packet` will be `None` on EOF. We want to pass it down to + # handle_recv_packet anyway so the main thread can handle unexpected + # termination of lldb-dap and stop waiting for new packets. + if not self._handle_recv_packet(packet): + break + finally: + dump_dap_log(self.log_file) def get_modules( self, start_module: Optional[int] = None, module_count: Optional[int] = None @@ -299,6 +310,34 @@ class DebugCommunication(object): output += self.get_output(category, clear=clear) return output + def _enqueue_recv_packet(self, packet: Optional[ProtocolMessage]): + with self.recv_condition: + self.recv_packets.append(packet) + self.recv_condition.notify() + + def _handle_recv_packet(self, packet: Optional[ProtocolMessage]) -> bool: + """Handles an incoming packet. + + Called by the read thread that is waiting for all incoming packets + to store the incoming packet in "self._recv_packets" in a thread safe + way. This function will then signal the "self._recv_condition" to + indicate a new packet is available. + + Args: + packet: A new packet to store. + + Returns: + True if the caller should keep calling this function for more + packets. + """ + with self._recv_condition: + self._recv_packets.append(packet) + self._recv_condition.notify() + # packet is None on EOF + return packet is not None and not ( + packet["type"] == "response" and packet["command"] == "disconnect" + ) + def _recv_packet( self, *, @@ -322,34 +361,46 @@ class DebugCommunication(object): The first matching packet for the given predicate, if specified, otherwise None. """ - deadline = time.time() + timeout - - while time.time() < deadline: - packet = self._read_packet(timeout=deadline - time.time()) - if packet is None: - return None - self._process_recv_packet(packet) - if not predicate or predicate(packet): - return packet - - def _process_recv_packet(self, packet) -> None: + assert ( + threading.current_thread != self._recv_thread + ), "Must not be called from the _recv_thread" + + def process_until_match(): + self._process_recv_packets() + for i, packet in enumerate(self._pending_packets): + if packet is None: + # We need to return a truthy value to break out of the + # wait_for, use `EOFError` as an indicator of EOF. + return EOFError() + if predicate and predicate(packet): + self._pending_packets.pop(i) + return packet + + with self._recv_condition: + packet = self._recv_condition.wait_for(process_until_match, timeout) + return None if isinstance(packet, EOFError) else packet + + def _process_recv_packets(self) -> None: """Process received packets, updating the session state.""" - if packet and ("seq" not in packet or packet["seq"] == 0): - warnings.warn( - f"received a malformed packet, expected 'seq != 0' for {packet!r}" - ) - # Handle events that may modify any stateful properties of - # the DAP session. - if packet and packet["type"] == "event": - self._handle_event(packet) - elif packet and packet["type"] == "request": - # Handle reverse requests and keep processing. - self._handle_reverse_request(packet) + with self._recv_condition: + for packet in self._recv_packets: + if packet and ("seq" not in packet or packet["seq"] == 0): + warnings.warn( + f"received a malformed packet, expected 'seq != 0' for {packet!r}" + ) + # Handle events that may modify any stateful properties of + # the DAP session. + if packet and packet["type"] == "event": + self._handle_event(packet) + elif packet and packet["type"] == "request": + # Handle reverse requests and keep processing. + self._handle_reverse_request(packet) + # Move the packet to the pending queue. + self._pending_packets.append(packet) + self._recv_packets.clear() def _handle_event(self, packet: Event) -> None: """Handle any events that modify debug session state we track.""" - self.events.append(packet) - event = packet["event"] body: Optional[Dict] = packet.get("body", None) @@ -402,8 +453,6 @@ class DebugCommunication(object): self.invalidated_event = packet elif event == "memory": self.memory_event = packet - elif event == "module": - self.module_events.append(packet) def _handle_reverse_request(self, request: Request) -> None: if request in self.reverse_requests: @@ -472,14 +521,18 @@ class DebugCommunication(object): Returns the seq number of the request. """ - packet["seq"] = self.sequence - self.sequence += 1 + # Set the seq for requests. + if packet["type"] == "request": + packet["seq"] = self.sequence + self.sequence += 1 + else: + packet["seq"] = 0 # Encode our command dictionary as a JSON string json_str = json.dumps(packet, separators=(",", ":")) if self.trace_file: - self.trace_file.write("%s to adapter:\n%s\n" % (time.time(), json_str)) + self.trace_file.write("to adapter:\n%s\n" % (json_str)) length = len(json_str) if length > 0: @@ -860,8 +913,6 @@ class DebugCommunication(object): if restartArguments: command_dict["arguments"] = restartArguments - # Clear state, the process is about to restart... - self._process_continued(True) response = self._send_recv(command_dict) # Caller must still call wait_for_stopped. return response @@ -1428,10 +1479,8 @@ class DebugCommunication(object): def terminate(self): self.send.close() - self.recv.close() - self.selector.close() - if self.log_file: - dump_dap_log(self.log_file) + if self._recv_thread.is_alive(): + self._recv_thread.join() def request_setInstructionBreakpoints(self, memory_reference=[]): breakpoints = [] @@ -1528,7 +1577,6 @@ class DebugAdapterServer(DebugCommunication): stdout=subprocess.PIPE, stderr=sys.stderr, env=adapter_env, - bufsize=0, ) if connection is None: diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 405e91f..c6c4a3e 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -15,8 +15,6 @@ import base64 # DAP tests as a whole have been flakey on the Windows on Arm bot. See: # https://github.com/llvm/llvm-project/issues/137660 @skipIf(oslist=["windows"], archs=["aarch64"]) -# The Arm Linux bot needs stable resources before it can run these tests reliably. -@skipIf(oslist=["linux"], archs=["arm$"]) class DAPTestCaseBase(TestBase): # set timeout based on whether ASAN was enabled or not. Increase # timeout by a factor of 10 if ASAN is enabled. @@ -225,6 +223,16 @@ class DAPTestCaseBase(TestBase): return True return False + def verify_stop_on_entry(self) -> None: + """Waits for the process to be stopped and then verifies at least one + thread has the stop reason 'entry'.""" + self.dap_server.wait_for_stopped() + self.assertIn( + "entry", + (t["reason"] for t in self.dap_server.thread_stop_reasons.values()), + "Expected at least one thread to report stop reason 'entry' in {self.dap_server.thread_stop_reasons}", + ) + def verify_commands(self, flavor: str, output: str, commands: list[str]): self.assertTrue(output and len(output) > 0, "expect console output") lines = output.splitlines() @@ -418,7 +426,7 @@ class DAPTestCaseBase(TestBase): return self.dap_server.wait_for_stopped() def continue_to_breakpoint(self, breakpoint_id: str): - self.continue_to_breakpoints([breakpoint_id]) + self.continue_to_breakpoints((breakpoint_id)) def continue_to_breakpoints(self, breakpoint_ids): self.do_continue() diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index b23d114..201d8d2 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -1098,14 +1098,9 @@ bool Breakpoint::EvaluatePrecondition(StoppointCallbackContext &context) { } void Breakpoint::SendBreakpointChangedEvent( - lldb::BreakpointEventType eventKind) { - if (!IsInternal() && GetTarget().EventTypeHasListeners( - Target::eBroadcastBitBreakpointChanged)) { - std::shared_ptr<BreakpointEventData> data = - std::make_shared<BreakpointEventData>(eventKind, shared_from_this()); - - GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data); - } + lldb::BreakpointEventType event_kind) { + if (!IsInternal()) + GetTarget().NotifyBreakpointChanged(*this, event_kind); } void Breakpoint::SendBreakpointChangedEvent( @@ -1113,10 +1108,8 @@ void Breakpoint::SendBreakpointChangedEvent( if (!breakpoint_data_sp) return; - if (!IsInternal() && - GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) - GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, - breakpoint_data_sp); + if (!IsInternal()) + GetTarget().NotifyBreakpointChanged(*this, breakpoint_data_sp); } const char *Breakpoint::BreakpointEventTypeAsCString(BreakpointEventType type) { diff --git a/lldb/source/Breakpoint/BreakpointList.cpp b/lldb/source/Breakpoint/BreakpointList.cpp index 779490a..e3dd62b 100644 --- a/lldb/source/Breakpoint/BreakpointList.cpp +++ b/lldb/source/Breakpoint/BreakpointList.cpp @@ -16,13 +16,7 @@ using namespace lldb; using namespace lldb_private; static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) { - Target &target = bp->GetTarget(); - if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) { - auto event_data_sp = - std::make_shared<Breakpoint::BreakpointEventData>(event, bp); - target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged, - event_data_sp); - } + bp->GetTarget().NotifyBreakpointChanged(*bp, event); } BreakpointList::BreakpointList(bool is_internal) diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp index 22c98ac..f25209c 100644 --- a/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -749,13 +749,11 @@ void BreakpointLocation::Dump(Stream *s) const { void BreakpointLocation::SendBreakpointLocationChangedEvent( lldb::BreakpointEventType eventKind) { - if (!m_owner.IsInternal() && m_owner.GetTarget().EventTypeHasListeners( - Target::eBroadcastBitBreakpointChanged)) { + if (!m_owner.IsInternal()) { auto data_sp = std::make_shared<Breakpoint::BreakpointEventData>( eventKind, m_owner.shared_from_this()); data_sp->GetBreakpointLocationCollection().Add(shared_from_this()); - m_owner.GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged, - data_sp); + m_owner.GetTarget().NotifyBreakpointChanged(m_owner, data_sp); } } diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp index f786866..097173f 100644 --- a/lldb/source/Core/SourceManager.cpp +++ b/lldb/source/Core/SourceManager.cpp @@ -34,6 +34,7 @@ #include "llvm/ADT/Twine.h" +#include <future> #include <memory> #include <optional> #include <utility> @@ -54,8 +55,7 @@ using namespace lldb_private; static inline bool is_newline_char(char ch) { return ch == '\n' || ch == '\r'; } static void resolve_tilde(FileSpec &file_spec) { - if (!FileSystem::Instance().Exists(file_spec) && - file_spec.GetDirectory() && + if (!FileSystem::Instance().Exists(file_spec) && file_spec.GetDirectory() && file_spec.GetDirectory().GetCString()[0] == '~') { FileSystem::Instance().Resolve(file_spec); } @@ -477,6 +477,28 @@ SourceManager::File::File(SupportFileSP support_file_sp, TargetSP target_sp) void SourceManager::File::CommonInitializer(SupportFileSP support_file_sp, TargetSP target_sp) { + // It might take a while to read a source file, for example because it's + // coming from a virtual file system that's fetching the data on demand. When + // reading the data exceeds a certain threshold, show a progress event to let + // the user know what's going on. + static constexpr auto g_progress_delay = std::chrono::milliseconds(500); + + std::future<void> future = std::async(std::launch::async, [=]() { + CommonInitializerImpl(support_file_sp, target_sp); + }); + + std::optional<Progress> progress; + if (future.wait_for(g_progress_delay) == std::future_status::timeout) { + Debugger *debugger = target_sp ? &target_sp->GetDebugger() : nullptr; + progress.emplace("Loading source file", + support_file_sp->GetSpecOnly().GetFilename().GetString(), + 1, debugger); + } + future.wait(); +} + +void SourceManager::File::CommonInitializerImpl(SupportFileSP support_file_sp, + TargetSP target_sp) { // Set the file and update the modification time. SetSupportFile(support_file_sp); diff --git a/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp index f9c249d..e41a28b 100644 --- a/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp +++ b/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp @@ -480,11 +480,10 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, } // Floating point return type. else if (type_flags & eTypeIsFloat) { - uint32_t float_count = 0; bool is_complex = false; - if (compiler_type.IsFloatingPointType(float_count, is_complex) && - 1 == float_count && !is_complex) { + if (compiler_type.IsFloatingPointType(is_complex) && + !compiler_type.IsVectorType() && !is_complex) { const size_t byte_size = llvm::expectedToOptional(compiler_type.GetByteSize(&thread)) .value_or(0); diff --git a/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp index 5b5f6fa..8e69021 100644 --- a/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp +++ b/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp @@ -1695,7 +1695,6 @@ Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -1767,7 +1766,7 @@ Status ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); diff --git a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp index bb0c4ba..7258f5c 100644 --- a/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp +++ b/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp @@ -1550,7 +1550,6 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( bool is_signed; bool is_complex; - uint32_t float_count; bool is_vfp_candidate = false; uint8_t vfp_count = 0; uint8_t vfp_byte_size = 0; @@ -1634,8 +1633,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( if (!GetReturnValuePassedInMemory(thread, reg_ctx, *byte_size, value)) return return_valobj_sp; } - } else if (compiler_type.IsFloatingPointType(float_count, is_complex)) { - if (float_count == 1 && !is_complex) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { + // Vector types are handled above. + if (!is_complex) { switch (*bit_width) { default: return return_valobj_sp; @@ -1681,7 +1681,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( break; } } - } else if (is_complex && float_count == 2) { + } else if (is_complex) { if (IsArmHardFloat(thread)) { is_vfp_candidate = true; vfp_byte_size = *byte_size / 2; @@ -1709,8 +1709,9 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( vfp_count = (*base_byte_size == 8 ? homogeneous_count : homogeneous_count * 2); } - } else if (base_type.IsFloatingPointType(float_count, is_complex)) { - if (float_count == 1 && !is_complex) { + } else if (base_type.IsFloatingPointType(is_complex)) { + // Vector types are handled above. + if (!is_complex) { is_vfp_candidate = true; if (base_byte_size) vfp_byte_size = *base_byte_size; @@ -1727,10 +1728,10 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( base_type = compiler_type.GetFieldAtIndex(index, name, nullptr, nullptr, nullptr); - if (base_type.IsFloatingPointType(float_count, is_complex)) { + if (base_type.IsFloatingPointType(is_complex)) { std::optional<uint64_t> base_byte_size = llvm::expectedToOptional(base_type.GetByteSize(&thread)); - if (float_count == 2 && is_complex) { + if (is_complex) { if (index != 0 && base_byte_size && vfp_byte_size != *base_byte_size) break; @@ -1841,7 +1842,6 @@ Status ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -1884,7 +1884,7 @@ Status ABISysV_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); diff --git a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp index 7bf99ce..4f5e29c 100644 --- a/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp +++ b/lldb/source/Plugins/ABI/LoongArch/ABISysV_loongarch.cpp @@ -510,11 +510,10 @@ ValueObjectSP ABISysV_loongarch::GetReturnValueObjectSimple( value, ConstString("")); } if (type_flags & eTypeIsFloat) { - uint32_t float_count = 0; bool is_complex = false; - if (compiler_type.IsFloatingPointType(float_count, is_complex) && - float_count == 1 && !is_complex) { + if (compiler_type.IsFloatingPointType(is_complex) && + !(type_flags & eTypeIsVector) && !is_complex) { return_valobj_sp = GetValObjFromFPRegs(thread, reg_ctx, machine, type_flags, byte_size); return return_valobj_sp; diff --git a/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp index dd91a05..e036044 100644 --- a/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp @@ -708,7 +708,6 @@ Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -750,7 +749,7 @@ Status ABISysV_mips::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); @@ -797,7 +796,6 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( bool is_signed = false; bool is_complex = false; - uint32_t count = 0; // In MIPS register "r2" (v0) holds the integer function return values const RegisterInfo *r2_reg_info = reg_ctx->GetRegisterInfoByName("r2", 0); @@ -860,10 +858,10 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( return_valobj_sp = ValueObjectMemory::Create( &thread, "", Address(mem_address, nullptr), return_compiler_type); return return_valobj_sp; - } else if (return_compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (return_compiler_type.IsFloatingPointType(is_complex)) { if (IsSoftFloat(fp_flag)) { uint64_t raw_value = reg_ctx->ReadRegisterAsUnsigned(r2_reg_info, 0); - if (count != 1 && is_complex) + if (is_complex) return return_valobj_sp; switch (*bit_width) { default: @@ -896,7 +894,7 @@ ValueObjectSP ABISysV_mips::GetReturnValueObjectImpl( f0_value.GetData(f0_data); lldb::offset_t offset = 0; - if (count == 1 && !is_complex) { + if (!return_compiler_type.IsVectorType() && !is_complex) { switch (*bit_width) { default: return return_valobj_sp; diff --git a/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp index baefbfc..0dd9db0 100644 --- a/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp +++ b/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp @@ -923,7 +923,6 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( bool sucess = false; std::string name; bool is_complex; - uint32_t count; const uint32_t num_children = return_compiler_type.GetNumFields(); // A structure consisting of one or two FP values (and nothing else) will @@ -937,7 +936,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, nullptr, nullptr); - if (field_compiler_type.IsFloatingPointType(count, is_complex)) + if (field_compiler_type.IsFloatingPointType(is_complex)) use_fp_regs = true; else found_non_fp_field = true; @@ -1044,7 +1043,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || field_compiler_type.IsPointerType() || - field_compiler_type.IsFloatingPointType(count, is_complex)) { + field_compiler_type.IsFloatingPointType(is_complex)) { padding = field_byte_offset - integer_bytes; if (integer_bytes < 8) { diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp index e4bdc44..0d25fae 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp @@ -426,7 +426,6 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -454,7 +453,7 @@ Status ABISysV_ppc::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); @@ -695,7 +694,6 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( uint64_t field_bit_offset = 0; bool is_signed; bool is_complex; - uint32_t count; CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); @@ -741,7 +739,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( // return a nullptr return value object. return return_valobj_sp; } - } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (field_compiler_type.IsFloatingPointType(is_complex)) { // Structs with long doubles are always passed in memory. if (*field_bit_width == 128) { is_memory = true; diff --git a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index f5327a1..6335761 100644 --- a/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -309,7 +309,6 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -339,7 +338,7 @@ Status ABISysV_ppc64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); diff --git a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp index 822c93d..53f11b5 100644 --- a/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp +++ b/lldb/source/Plugins/ABI/RISCV/ABISysV_riscv.cpp @@ -643,11 +643,10 @@ ABISysV_riscv::GetReturnValueObjectSimple(Thread &thread, } // Floating point return type. else if (type_flags & eTypeIsFloat) { - uint32_t float_count = 0; bool is_complex = false; - if (compiler_type.IsFloatingPointType(float_count, is_complex) && - float_count == 1 && !is_complex) { + if (compiler_type.IsFloatingPointType(is_complex) && + !(type_flags & eTypeIsVector) && !is_complex) { const uint32_t arch_fp_flags = arch.GetFlags() & ArchSpec::eRISCV_float_abi_mask; return_valobj_sp = GetValObjFromFPRegs( diff --git a/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp index 5e52b6e..301c3b3 100644 --- a/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp +++ b/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp @@ -393,7 +393,6 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -423,7 +422,7 @@ Status ABISysV_s390x::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); diff --git a/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp index eaeed6c..ee79abe 100644 --- a/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp +++ b/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp @@ -198,7 +198,6 @@ Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -240,7 +239,7 @@ Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); diff --git a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp index effb3de..29fd9f0 100644 --- a/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp +++ b/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp @@ -307,7 +307,6 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -337,7 +336,7 @@ Status ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); @@ -587,7 +586,6 @@ static bool FlattenAggregateType( for (uint32_t idx = 0; idx < num_children; ++idx) { std::string name; bool is_signed; - uint32_t count; bool is_complex; uint64_t field_bit_offset = 0; @@ -606,7 +604,7 @@ static bool FlattenAggregateType( const uint32_t field_type_flags = field_compiler_type.GetTypeInfo(); if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || field_compiler_type.IsPointerType() || - field_compiler_type.IsFloatingPointType(count, is_complex)) { + field_compiler_type.IsFloatingPointType(is_complex)) { aggregate_field_offsets.push_back(field_byte_offset); aggregate_compiler_types.push_back(field_compiler_type); } else if (field_type_flags & eTypeHasChildren) { @@ -696,7 +694,6 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( is_memory = false; for (uint32_t idx = 0; idx < num_children; idx++) { bool is_signed; - uint32_t count; bool is_complex; CompilerType field_compiler_type = aggregate_compiler_types[idx]; @@ -736,7 +733,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectImpl( // return a nullptr return value object. return return_valobj_sp; } - } else if (field_compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (field_compiler_type.IsFloatingPointType(is_complex)) { // Structs with long doubles are always passed in memory. if (field_bit_width == 128) { is_memory = true; diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp index 339012c..6520af2 100644 --- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp +++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp @@ -312,7 +312,6 @@ Status ABIWindows_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, Thread *thread = frame_sp->GetThread().get(); bool is_signed; - uint32_t count; bool is_complex; RegisterContext *reg_ctx = thread->GetRegisterContext().get(); @@ -342,7 +341,7 @@ Status ABIWindows_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, "We don't support returning longer than 64 bit " "integer values at present."); } - } else if (compiler_type.IsFloatingPointType(count, is_complex)) { + } else if (compiler_type.IsFloatingPointType(is_complex)) { if (is_complex) error = Status::FromErrorString( "We don't support returning complex values at present"); @@ -558,7 +557,6 @@ static bool FlattenAggregateType( for (uint32_t idx = 0; idx < num_children; ++idx) { std::string name; bool is_signed; - uint32_t count; bool is_complex; uint64_t field_bit_offset = 0; @@ -582,7 +580,7 @@ static bool FlattenAggregateType( const uint32_t field_type_flags = field_compiler_type.GetTypeInfo(); if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || field_compiler_type.IsPointerType() || - field_compiler_type.IsFloatingPointType(count, is_complex)) { + field_compiler_type.IsFloatingPointType(is_complex)) { aggregate_field_offsets.push_back(field_byte_offset); aggregate_compiler_types.push_back(field_compiler_type); } else if (field_type_flags & eTypeHasChildren) { @@ -672,7 +670,6 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectImpl( for (uint32_t idx = 0; idx < num_children; idx++) { bool is_signed; bool is_complex; - uint32_t count; CompilerType field_compiler_type = aggregate_compiler_types[idx]; uint32_t field_byte_width = @@ -691,7 +688,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectImpl( uint32_t copy_from_offset = 0; if (field_compiler_type.IsIntegerOrEnumerationType(is_signed) || field_compiler_type.IsPointerType() || - field_compiler_type.IsFloatingPointType(count, is_complex)) { + field_compiler_type.IsFloatingPointType(is_complex)) { copy_from_extractor = &rax_data; copy_from_offset = used_bytes; used_bytes += field_byte_width; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c049829..63b2dc4 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -814,13 +814,18 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, // there... [[fallthrough]]; - case DW_TAG_base_type: + case DW_TAG_base_type: { resolve_state = Type::ResolveState::Full; + // If a builtin type's size isn't a multiple of a byte, DWARF producers may + // add a precise bit-size to the type. Use the most precise bit-size + // possible. + const uint64_t bit_size = attrs.data_bit_size + ? *attrs.data_bit_size + : attrs.byte_size.value_or(0) * 8; clang_type = m_ast.GetBuiltinTypeForDWARFEncodingAndBitSize( - attrs.name.GetStringRef(), attrs.encoding, - attrs.byte_size.value_or(0) * 8); + attrs.name.GetStringRef(), attrs.encoding, bit_size); break; - + } case DW_TAG_pointer_type: encoding_data_type = Type::eEncodingIsPointerUID; break; @@ -2047,11 +2052,10 @@ static std::optional<clang::APValue> MakeAPValue(const clang::ASTContext &ast, if (is_integral) return clang::APValue(apint); - uint32_t count; bool is_complex; // FIXME: we currently support a limited set of floating point types. // E.g., 16-bit floats are not supported. - if (!clang_type.IsFloatingPointType(count, is_complex)) + if (!clang_type.IsFloatingPointType(is_complex)) return std::nullopt; return clang::APValue(llvm::APFloat( diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index d90108f..36dee14 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -22,7 +22,6 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" #include "lldb/lldb-private-enumerations.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ThreadPool.h" #include <atomic> #include <optional> @@ -33,10 +32,10 @@ using namespace lldb_private::plugin::dwarf; using namespace llvm::dwarf; void ManualDWARFIndex::Index() { - if (m_indexed) - return; - m_indexed = true; + std::call_once(m_indexed_flag, [this]() { IndexImpl(); }); +} +void ManualDWARFIndex::IndexImpl() { ElapsedTime elapsed(m_index_time); LLDB_SCOPED_TIMERF("%p", static_cast<void *>(m_dwarf)); if (LoadFromCache()) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index 0b5b2f3..41e0e62 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -66,8 +66,14 @@ public: void Dump(Stream &s) override; private: + /// Reads the DWARF debug info to build the index once. + /// + /// Should be called before attempting to retrieve symbols. void Index(); + /// Call `ManualDWARFIndex::Index()` instead. + void IndexImpl(); + /// Decode a serialized version of this object from data. /// /// \param data @@ -170,7 +176,7 @@ private: llvm::DenseSet<uint64_t> m_type_sigs_to_avoid; IndexSet<NameToDIE> m_set; - bool m_indexed = false; + std::once_flag m_indexed_flag; }; } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index e76b7a3..aaec160 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1130,7 +1130,35 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { if (!section_list) return; - for (auto pid : m_index->publics().getPublicsTable()) { + PublicSym32 last_sym; + size_t last_sym_idx = 0; + lldb::SectionSP section_sp; + + // To estimate the size of a symbol, we use the difference to the next symbol. + // If there's no next symbol or the section/segment changed, the symbol will + // take the remaining space. The estimate can be too high in case there's + // padding between symbols. This similar to the algorithm used by the DIA + // SDK. + auto finish_last_symbol = [&](const PublicSym32 *next) { + if (!section_sp) + return; + Symbol *last = symtab.SymbolAtIndex(last_sym_idx); + if (!last) + return; + + if (next && last_sym.Segment == next->Segment) { + assert(last_sym.Offset <= next->Offset); + last->SetByteSize(next->Offset - last_sym.Offset); + } else { + // the last symbol was the last in its section + assert(section_sp->GetByteSize() >= last_sym.Offset); + assert(!next || next->Segment > last_sym.Segment); + last->SetByteSize(section_sp->GetByteSize() - last_sym.Offset); + } + }; + + // The address map is sorted by the address of a symbol. + for (auto pid : m_index->publics().getAddressMap()) { PdbGlobalSymId global{pid, true}; CVSymbol sym = m_index->ReadSymbolRecord(global); auto kind = sym.kind(); @@ -1138,8 +1166,11 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { continue; PublicSym32 pub = llvm::cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(sym)); + finish_last_symbol(&pub); + + if (!section_sp || last_sym.Segment != pub.Segment) + section_sp = section_list->FindSectionByID(pub.Segment); - auto section_sp = section_list->FindSectionByID(pub.Segment); if (!section_sp) continue; @@ -1148,20 +1179,24 @@ void SymbolFileNativePDB::AddSymbols(Symtab &symtab) { (pub.Flags & PublicSymFlags::Code) != PublicSymFlags::None) type = eSymbolTypeCode; - symtab.AddSymbol(Symbol(/*symID=*/pid, - /*name=*/pub.Name, - /*type=*/type, - /*external=*/true, - /*is_debug=*/true, - /*is_trampoline=*/false, - /*is_artificial=*/false, - /*section_sp=*/section_sp, - /*value=*/pub.Offset, - /*size=*/0, - /*size_is_valid=*/false, - /*contains_linker_annotations=*/false, - /*flags=*/0)); - } + last_sym_idx = + symtab.AddSymbol(Symbol(/*symID=*/pid, + /*name=*/pub.Name, + /*type=*/type, + /*external=*/true, + /*is_debug=*/true, + /*is_trampoline=*/false, + /*is_artificial=*/false, + /*section_sp=*/section_sp, + /*value=*/pub.Offset, + /*size=*/0, + /*size_is_valid=*/false, + /*contains_linker_annotations=*/false, + /*flags=*/0)); + last_sym = pub; + } + + finish_last_symbol(nullptr); } size_t SymbolFileNativePDB::ParseFunctions(CompileUnit &comp_unit) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 6ec054d..51cb883 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1000,6 +1000,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( case DW_ATE_signed: if (!type_name.empty()) { + if (type_name.starts_with("_BitInt")) + return GetType(ast.getBitIntType(/*Unsigned=*/false, bit_size)); if (type_name == "wchar_t" && QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy) && (getTargetInfo() && @@ -1056,6 +1058,8 @@ CompilerType TypeSystemClang::GetBuiltinTypeForDWARFEncodingAndBitSize( case DW_ATE_unsigned: if (!type_name.empty()) { + if (type_name.starts_with("unsigned _BitInt")) + return GetType(ast.getBitIntType(/*Unsigned=*/true, bit_size)); if (type_name == "wchar_t") { if (QualTypeMatchesBitSize(bit_size, ast, ast.WCharTy)) { if (!(getTargetInfo() && @@ -3488,7 +3492,7 @@ bool TypeSystemClang::IsReferenceType(lldb::opaque_compiler_type_t type, } bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type, - uint32_t &count, bool &is_complex) { + bool &is_complex) { if (type) { clang::QualType qual_type(GetCanonicalQualType(type)); @@ -3497,30 +3501,26 @@ bool TypeSystemClang::IsFloatingPointType(lldb::opaque_compiler_type_t type, clang::BuiltinType::Kind kind = BT->getKind(); if (kind >= clang::BuiltinType::Float && kind <= clang::BuiltinType::LongDouble) { - count = 1; is_complex = false; return true; } } else if (const clang::ComplexType *CT = llvm::dyn_cast<clang::ComplexType>( qual_type->getCanonicalTypeInternal())) { - if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, + if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), is_complex)) { - count = 2; is_complex = true; return true; } } else if (const clang::VectorType *VT = llvm::dyn_cast<clang::VectorType>( qual_type->getCanonicalTypeInternal())) { - if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, + if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), is_complex)) { - count = VT->getNumElements(); is_complex = false; return true; } } } - count = 0; is_complex = false; return false; } @@ -3893,6 +3893,13 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, ->getModifiedType() .getAsOpaquePtr(), pointee_or_element_clang_type); + case clang::Type::BitInt: { + uint32_t type_flags = eTypeIsScalar | eTypeIsInteger | eTypeHasValue; + if (qual_type->isSignedIntegerType()) + type_flags |= eTypeIsSigned; + + return type_flags; + } case clang::Type::Builtin: { const clang::BuiltinType *builtin_type = llvm::cast<clang::BuiltinType>(qual_type->getCanonicalTypeInternal()); @@ -3965,9 +3972,9 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, if (complex_type) { clang::QualType complex_element_type(complex_type->getElementType()); if (complex_element_type->isIntegerType()) - complex_type_flags |= eTypeIsFloat; - else if (complex_element_type->isFloatingType()) complex_type_flags |= eTypeIsInteger; + else if (complex_element_type->isFloatingType()) + complex_type_flags |= eTypeIsFloat; } return complex_type_flags; } break; @@ -4062,12 +4069,17 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector; const clang::VectorType *vector_type = llvm::dyn_cast<clang::VectorType>( qual_type->getCanonicalTypeInternal()); - if (vector_type) { - if (vector_type->isIntegerType()) - vector_type_flags |= eTypeIsFloat; - else if (vector_type->isFloatingType()) - vector_type_flags |= eTypeIsInteger; - } + if (!vector_type) + return 0; + + QualType element_type = vector_type->getElementType(); + if (element_type.isNull()) + return 0; + + if (element_type->isIntegerType()) + vector_type_flags |= eTypeIsInteger; + else if (element_type->isFloatingType()) + vector_type_flags |= eTypeIsFloat; return vector_type_flags; } default: @@ -4864,12 +4876,10 @@ TypeSystemClang::GetTypeBitAlign(lldb::opaque_compiler_type_t type, return {}; } -lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, - uint64_t &count) { +lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type) { if (!type) return lldb::eEncodingInvalid; - count = 1; clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); switch (qual_type->getTypeClass()) { @@ -4903,7 +4913,6 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::DependentVector: case clang::Type::ExtVector: case clang::Type::Vector: - // TODO: Set this to more than one??? break; case clang::Type::BitInt: @@ -5104,11 +5113,10 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, const clang::ComplexType *complex_type = qual_type->getAsComplexIntegerType(); if (complex_type) - encoding = GetType(complex_type->getElementType()).GetEncoding(count); + encoding = GetType(complex_type->getElementType()).GetEncoding(); else encoding = lldb::eEncodingSint; } - count = 2; return encoding; } @@ -5165,7 +5173,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::Type::SubstBuiltinTemplatePack: break; } - count = 0; + return lldb::eEncodingInvalid; } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 9e0a542..375891b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -651,7 +651,7 @@ public: bool IsDefined(lldb::opaque_compiler_type_t type) override; - bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, + bool IsFloatingPointType(lldb::opaque_compiler_type_t type, bool &is_complex) override; unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) override; @@ -837,8 +837,7 @@ public: GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; - lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type, - uint64_t &count) override; + lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type) override; lldb::Format GetFormat(lldb::opaque_compiler_type_t type) override; diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 62c0ddf..c999ab2 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -240,13 +240,11 @@ bool CompilerType::ShouldTreatScalarValueAsAddress() const { return false; } -bool CompilerType::IsFloatingPointType(uint32_t &count, - bool &is_complex) const { +bool CompilerType::IsFloatingPointType(bool &is_complex) const { if (IsValid()) { if (auto type_system_sp = GetTypeSystem()) - return type_system_sp->IsFloatingPointType(m_type, count, is_complex); + return type_system_sp->IsFloatingPointType(m_type, is_complex); } - count = 0; is_complex = false; return false; } @@ -331,9 +329,8 @@ bool CompilerType::IsInteger() const { } bool CompilerType::IsFloat() const { - uint32_t count = 0; bool is_complex = false; - return IsFloatingPointType(count, is_complex); + return IsFloatingPointType(is_complex); } bool CompilerType::IsEnumerationType() const { @@ -793,10 +790,10 @@ CompilerType::GetTypeBitAlign(ExecutionContextScope *exe_scope) const { return {}; } -lldb::Encoding CompilerType::GetEncoding(uint64_t &count) const { +lldb::Encoding CompilerType::GetEncoding() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) - return type_system_sp->GetEncoding(m_type, count); + return type_system_sp->GetEncoding(m_type); return lldb::eEncodingInvalid; } @@ -1093,10 +1090,10 @@ bool CompilerType::GetValueAsScalar(const lldb_private::DataExtractor &data, if (IsAggregateType()) { return false; // Aggregate types don't have scalar values } else { - uint64_t count = 0; - lldb::Encoding encoding = GetEncoding(count); + // FIXME: check that type is scalar instead of checking encoding? + lldb::Encoding encoding = GetEncoding(); - if (encoding == lldb::eEncodingInvalid || count != 1) + if (encoding == lldb::eEncodingInvalid || (GetTypeInfo() & eTypeIsComplex)) return false; auto byte_size_or_err = GetByteSize(exe_scope); diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 952b2bd..0c3246d 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -531,9 +531,9 @@ lldb::TypeSP Type::GetTypedefType() { lldb::Format Type::GetFormat() { return GetForwardCompilerType().GetFormat(); } -lldb::Encoding Type::GetEncoding(uint64_t &count) { +lldb::Encoding Type::GetEncoding() { // Make sure we resolve our type if it already hasn't been. - return GetForwardCompilerType().GetEncoding(count); + return GetForwardCompilerType().GetEncoding(); } bool Type::ReadFromMemory(ExecutionContext *exe_ctx, lldb::addr_t addr, diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index d070c3d..1e43094 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/Target.h" +#include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Breakpoint/BreakpointResolver.h" @@ -5271,3 +5272,19 @@ void Target::ClearSectionLoadList() { GetSectionLoadList().Clear(); } void Target::DumpSectionLoadList(Stream &s) { GetSectionLoadList().Dump(s, this); } + +void Target::NotifyBreakpointChanged(Breakpoint &bp, + lldb::BreakpointEventType eventKind) { + if (EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) { + std::shared_ptr<Breakpoint::BreakpointEventData> data_sp = + std::make_shared<Breakpoint::BreakpointEventData>( + eventKind, bp.shared_from_this()); + BroadcastEvent(Target::eBroadcastBitBreakpointChanged, data_sp); + } +} + +void Target::NotifyBreakpointChanged( + Breakpoint &bp, const lldb::EventDataSP &breakpoint_data_sp) { + if (EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) + BroadcastEvent(Target::eBroadcastBitBreakpointChanged, breakpoint_data_sp); +} diff --git a/lldb/source/ValueObject/ValueObject.cpp b/lldb/source/ValueObject/ValueObject.cpp index 38b9f77..aeea32f 100644 --- a/lldb/source/ValueObject/ValueObject.cpp +++ b/lldb/source/ValueObject/ValueObject.cpp @@ -790,8 +790,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { return false; } - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding(count); + const Encoding encoding = GetCompilerType().GetEncoding(); const size_t byte_size = llvm::expectedToOptional(GetByteSize()).value_or(0); @@ -1669,8 +1668,7 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { return false; } - uint64_t count = 0; - const Encoding encoding = GetCompilerType().GetEncoding(count); + const Encoding encoding = GetCompilerType().GetEncoding(); const size_t byte_size = llvm::expectedToOptional(GetByteSize()).value_or(0); diff --git a/lldb/test/API/functionalities/multiple-slides/TestMultipleSlides.py b/lldb/test/API/functionalities/multiple-slides/TestMultipleSlides.py index 7fd2ff4..5fd2b76 100644 --- a/lldb/test/API/functionalities/multiple-slides/TestMultipleSlides.py +++ b/lldb/test/API/functionalities/multiple-slides/TestMultipleSlides.py @@ -12,10 +12,6 @@ from lldbsuite.test import lldbutil class MultipleSlidesTestCase(TestBase): NO_DEBUG_INFO_TESTCASE = True - # The intermediate object main.o is compiled without debug info, but - # a.out is linked with `-gdwarf` on Windows. This creates a PDB. - # However, in the native PDB plugin, the symbols don't have a size. - @expectedFailureWindows def test_mulitple_slides(self): """Test that a binary can be slid multiple times correctly.""" self.build() @@ -33,10 +29,13 @@ class MultipleSlidesTestCase(TestBase): first_sym.GetEndAddress().GetOffset() - first_sym.GetStartAddress().GetOffset() ) + int_size = target.FindFirstType("int").GetByteSize() + self.assertGreaterEqual(first_size, 2048 * int_size) second_size = ( second_sym.GetEndAddress().GetOffset() - second_sym.GetStartAddress().GetOffset() ) + self.assertGreaterEqual(second_size, 2048 * int_size) # View the first element of `first` and `second` while # they have no load address set. diff --git a/lldb/test/API/lang/objc/real-definition/TestRealDefinition.py b/lldb/test/API/lang/objc/real-definition/TestRealDefinition.py index 6cbb9dd..9fb2bea9 100644 --- a/lldb/test/API/lang/objc/real-definition/TestRealDefinition.py +++ b/lldb/test/API/lang/objc/real-definition/TestRealDefinition.py @@ -27,13 +27,11 @@ class TestRealDefinition(TestBase): # Run at stop at main lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1) - self.runCmd("settings set target.prefer-dynamic-value no-dynamic-values") - # This should display correctly. self.expect( "frame variable foo->_bar->_hidden_ivar", VARIABLES_DISPLAYED_CORRECTLY, - substrs=["(NSString *)", "foo->_bar->_hidden_ivar = 0x"], + substrs=["foo->_bar->_hidden_ivar = 0x"], ) def test_frame_var_after_stop_at_implementation(self): @@ -54,11 +52,9 @@ class TestRealDefinition(TestBase): # Run at stop at main lldbutil.check_breakpoint(self, bpno=1, expected_hit_count=1) - self.runCmd("settings set target.prefer-dynamic-value no-dynamic-values") - # This should display correctly. self.expect( "frame variable foo->_bar->_hidden_ivar", VARIABLES_DISPLAYED_CORRECTLY, - substrs=["(NSString *)", "foo->_bar->_hidden_ivar = 0x"], + substrs=["foo->_bar->_hidden_ivar = 0x"], ) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py index 7b78541..beab4d6 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-events/TestDAP_breakpointEvents.py @@ -81,20 +81,24 @@ class TestDAP_breakpointEvents(lldbdap_testcase.DAPTestCaseBase): breakpoint["verified"], "expect foo breakpoint to not be verified" ) + # Flush the breakpoint events. + self.dap_server.wait_for_breakpoint_events() + # Continue to the breakpoint - self.continue_to_breakpoint(foo_bp_id) - self.continue_to_next_stop() # foo_bp2 - self.continue_to_breakpoint(main_bp_id) - self.continue_to_exit() + self.continue_to_breakpoints(dap_breakpoint_ids) - bp_events = [e for e in self.dap_server.events if e["event"] == "breakpoint"] + verified_breakpoint_ids = [] + unverified_breakpoint_ids = [] + for breakpoint_event in self.dap_server.wait_for_breakpoint_events(): + breakpoint = breakpoint_event["body"]["breakpoint"] + id = breakpoint["id"] + if breakpoint["verified"]: + verified_breakpoint_ids.append(id) + else: + unverified_breakpoint_ids.append(id) - main_bp_events = [ - e for e in bp_events if e["body"]["breakpoint"]["id"] == main_bp_id - ] - foo_bp_events = [ - e for e in bp_events if e["body"]["breakpoint"]["id"] == foo_bp_id - ] + self.assertIn(main_bp_id, unverified_breakpoint_ids) + self.assertIn(foo_bp_id, unverified_breakpoint_ids) - self.assertTrue(main_bp_events) - self.assertTrue(foo_bp_events) + self.assertIn(main_bp_id, verified_breakpoint_ids) + self.assertIn(foo_bp_id, verified_breakpoint_ids) diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 09b1322..ca881f1 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -156,7 +156,6 @@ class TestDAP_launch(lldbdap_testcase.DAPTestCaseBase): self.build_and_launch( program, debuggerRoot=program_parent_dir, initCommands=commands ) - self.continue_to_exit() output = self.get_console() self.assertTrue(output and len(output) > 0, "expect console output") lines = output.splitlines() @@ -172,6 +171,7 @@ class TestDAP_launch(lldbdap_testcase.DAPTestCaseBase): % (program_parent_dir, line[len(prefix) :]), ) self.assertTrue(found, "verified lldb-dap working directory") + self.continue_to_exit() def test_sourcePath(self): """ diff --git a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py index 9d1d17b..1f4afab 100644 --- a/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py +++ b/lldb/test/API/tools/lldb-dap/module-event/TestDAP_module_event.py @@ -1,58 +1,58 @@ -""" -Test 'module' events for dynamically loaded libraries. -""" - +import dap_server from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil import lldbdap_testcase +import re class TestDAP_module_event(lldbdap_testcase.DAPTestCaseBase): - def lookup_module_id(self, name): - """Returns the identifier for the first module event starting with the given name.""" - for event in self.dap_server.module_events: - if self.get_dict_value(event, ["body", "module", "name"]).startswith(name): - return self.get_dict_value(event, ["body", "module", "id"]) - self.fail(f"No module events matching name={name}") - - def module_events(self, id): - """Finds all module events by identifier.""" - return [ - event - for event in self.dap_server.module_events - if self.get_dict_value(event, ["body", "module", "id"]) == id - ] - - def module_reasons(self, events): - """Returns the list of 'reason' values from the given events.""" - return [event["body"]["reason"] for event in events] - @skipIfWindows def test_module_event(self): - """ - Test that module events are fired on target load and when the list of - dynamic libraries updates while running. - """ program = self.getBuildArtifact("a.out") self.build_and_launch(program) - # We can analyze the order of events after the process exits. - self.continue_to_exit() - a_out_id = self.lookup_module_id("a.out") - a_out_events = self.module_events(id=a_out_id) + source = "main.cpp" + breakpoint1_line = line_number(source, "// breakpoint 1") + breakpoint2_line = line_number(source, "// breakpoint 2") + breakpoint3_line = line_number(source, "// breakpoint 3") - self.assertIn( - "new", - self.module_reasons(a_out_events), - "Expected a.out to load during the debug session.", + breakpoint_ids = self.set_source_breakpoints( + source, [breakpoint1_line, breakpoint2_line, breakpoint3_line] ) + self.continue_to_breakpoints(breakpoint_ids) + + # We're now stopped at breakpoint 1 before the dlopen. Flush all the module events. + event = self.dap_server.wait_for_event(["module"]) + while event is not None: + event = self.dap_server.wait_for_event(["module"]) + + # Continue to the second breakpoint, before the dlclose. + self.continue_to_breakpoints(breakpoint_ids) + + # Make sure we got a module event for libother. + event = self.dap_server.wait_for_event(["module"]) + self.assertIsNotNone(event, "didn't get a module event") + module_name = event["body"]["module"]["name"] + module_id = event["body"]["module"]["id"] + self.assertEqual(event["body"]["reason"], "new") + self.assertIn("libother", module_name) + + # Continue to the third breakpoint, after the dlclose. + self.continue_to_breakpoints(breakpoint_ids) + + # Make sure we got a module event for libother. + event = self.dap_server.wait_for_event(["module"]) + self.assertIsNotNone(event, "didn't get a module event") + reason = event["body"]["reason"] + self.assertEqual(reason, "removed") + self.assertEqual(event["body"]["module"]["id"], module_id) + + # The removed module event should omit everything but the module id and name + # as they are required fields. + module_data = event["body"]["module"] + required_keys = ["id", "name"] + self.assertListEqual(list(module_data.keys()), required_keys) + self.assertEqual(module_data["name"], "", "expects empty name.") - libother_id = self.lookup_module_id( - "libother." # libother.so or libother.dylib based on OS. - ) - libother_events = self.module_events(id=libother_id) - self.assertEqual( - self.module_reasons(libother_events), - ["new", "removed"], - "Expected libother to be loaded then unloaded during the debug session.", - ) + self.continue_to_exit() diff --git a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py index 2d00c51..0ed53da 100644 --- a/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py +++ b/lldb/test/API/tools/lldb-dap/module/TestDAP_module.py @@ -64,18 +64,19 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): self.assertEqual(program, program_module["path"]) self.assertIn("addressRange", program_module) - self.continue_to_exit() - # Collect all the module names we saw as events. module_new_names = [] module_changed_names = [] - for module_event in self.dap_server.module_events: + module_event = self.dap_server.wait_for_event(["module"]) + while module_event is not None: reason = module_event["body"]["reason"] if reason == "new": module_new_names.append(module_event["body"]["module"]["name"]) elif reason == "changed": module_changed_names.append(module_event["body"]["module"]["name"]) + module_event = self.dap_server.wait_for_event(["module"]) + # Make sure we got an event for every active module. self.assertNotEqual(len(module_new_names), 0) for module in active_modules: @@ -85,6 +86,7 @@ class TestDAP_module(lldbdap_testcase.DAPTestCaseBase): # symbols got added. self.assertNotEqual(len(module_changed_names), 0) self.assertIn(program_module["name"], module_changed_names) + self.continue_to_exit() @skipIfWindows def test_modules(self): diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py index 83faf27..e8e07e1 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart.py @@ -51,20 +51,8 @@ class TestDAP_restart(lldbdap_testcase.DAPTestCaseBase): self.build_and_launch(program, stopOnEntry=True) [bp_main] = self.set_function_breakpoints(["main"]) - self.dap_server.request_configurationDone() - self.dap_server.wait_for_stopped() - # Once the "configuration done" event is sent, we should get a stopped - # event immediately because of stopOnEntry. - self.assertTrue( - len(self.dap_server.thread_stop_reasons) > 0, - "expected stopped event during launch", - ) - for _, body in self.dap_server.thread_stop_reasons.items(): - if "reason" in body: - reason = body["reason"] - self.assertNotEqual( - reason, "breakpoint", 'verify stop isn\'t "main" breakpoint' - ) + self.continue_to_next_stop() + self.verify_stop_on_entry() # Then, if we continue, we should hit the breakpoint at main. self.continue_to_breakpoints([bp_main]) @@ -73,17 +61,7 @@ class TestDAP_restart(lldbdap_testcase.DAPTestCaseBase): # main. resp = self.dap_server.request_restart() self.assertTrue(resp["success"]) - stopped_events = self.dap_server.wait_for_stopped() - for stopped_event in stopped_events: - if "body" in stopped_event: - body = stopped_event["body"] - if "reason" in body: - reason = body["reason"] - self.assertNotEqual( - reason, - "breakpoint", - 'verify stop after restart isn\'t "main" breakpoint', - ) + self.verify_stop_on_entry() @skipIfWindows def test_arguments(self): diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py index fa62ec2..7d49499 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_console.py @@ -11,31 +11,6 @@ from lldbsuite.test.lldbtest import line_number @skipIfBuildType(["debug"]) class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase): - def verify_stopped_on_entry(self, stopped_events: List[Dict[str, Any]]): - seen_stopped_event = 0 - for stopped_event in stopped_events: - body = stopped_event.get("body") - if body is None: - continue - - reason = body.get("reason") - if reason is None: - continue - - self.assertNotEqual( - reason, - "breakpoint", - 'verify stop after restart isn\'t "main" breakpoint', - ) - if reason == "entry": - seen_stopped_event += 1 - - self.assertEqual( - seen_stopped_event, - 1, - f"expect only one stopped entry event in {stopped_events}", - ) - @skipIfAsan @skipIfWindows @skipIf(oslist=["linux"], archs=["arm$"]) # Always times out on buildbot @@ -97,12 +72,7 @@ class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase): [bp_main] = self.set_function_breakpoints(["main"]) self.dap_server.request_configurationDone() - stopped_threads = list(self.dap_server.thread_stop_reasons.values()) - # We should be stopped at the entry point. - self.assertEqual( - len(stopped_threads), 1, "Expected the main thread to be stopped on entry." - ) - self.assertEqual(stopped_threads[0]["reason"], "entry") + self.verify_stop_on_entry() # Then, if we continue, we should hit the breakpoint at main. self.dap_server.request_continue() @@ -111,12 +81,7 @@ class TestDAP_restart_console(lldbdap_testcase.DAPTestCaseBase): # Restart and check that we still get a stopped event before reaching # main. self.dap_server.request_restart() - stopped_threads = list(self.dap_server.thread_stop_reasons.values()) - # We should be stopped at the entry point. - self.assertEqual( - len(stopped_threads), 1, "Expected the main thread to be stopped on entry." - ) - self.assertEqual(stopped_threads[0]["reason"], "entry") + self.verify_stop_on_entry() # continue to main self.dap_server.request_continue() diff --git a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py index 0184020..a018456 100644 --- a/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py +++ b/lldb/test/API/tools/lldb-dap/send-event/TestDAP_sendEvent.py @@ -32,7 +32,7 @@ class TestDAP_sendEvent(lldbdap_testcase.DAPTestCaseBase): ], ) self.set_source_breakpoints(source, [breakpoint_line]) - self.do_continue() + self.continue_to_next_stop() custom_event = self.dap_server.wait_for_event( filter=["my-custom-event-no-body"] diff --git a/lldb/test/Shell/SymbolFile/NativePDB/symtab.cpp b/lldb/test/Shell/SymbolFile/NativePDB/symtab.cpp index beb5ae2..75c59c5 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/symtab.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/symtab.cpp @@ -42,18 +42,18 @@ int main(int argc, char **argv) { return ns::a_function() + b.b_func(); } -// CHECK-DAG: Code {{.*}} main -// CHECK-DAG: Code {{.*}} ?b_func@?$B@F@ns@@QEBAHXZ -// CHECK-DAG: Code {{.*}} ?something@A@@QEAAXXZ -// CHECK-DAG: Code {{.*}} ??_GDyn@ns@@UEAAPEAXI@Z -// CHECK-DAG: Code {{.*}} ??2@YAPEAX_K@Z -// CHECK-DAG: Code {{.*}} ??3@YAXPEAX_K@Z -// CHECK-DAG: Code {{.*}} ?static_fn@C@?$B@H@ns@@SAHXZ -// CHECK-DAG: Code {{.*}} ?a_function@ns@@YAHXZ -// CHECK-DAG: Code {{.*}} ?static_fn@C@?$B@_N@ns@@SAHXZ -// CHECK-DAG: Code {{.*}} ??1Dyn@ns@@UEAA@XZ -// CHECK-DAG: Code {{.*}} ??0Dyn@ns@@QEAA@XZ -// CHECK-DAG: Data {{.*}} ?global_int@@3HA -// CHECK-DAG: Data {{.*}} ??_7Dyn@ns@@6B@ -// CHECK-DAG: Data {{.*}} ?global_a@@3UA@@A -// CHECK-DAG: Data {{.*}} ?global_c@@3UC@?$B@_J@ns@@A +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 main +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?b_func@?$B@F@ns@@QEBAHXZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?something@A@@QEAAXXZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??_GDyn@ns@@UEAAPEAXI@Z +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??2@YAPEAX_K@Z +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??3@YAXPEAX_K@Z +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?static_fn@C@?$B@H@ns@@SAHXZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?a_function@ns@@YAHXZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?static_fn@C@?$B@_N@ns@@SAHXZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??1Dyn@ns@@UEAA@XZ +// CHECK-DAG: Code 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??0Dyn@ns@@QEAA@XZ +// CHECK-DAG: Data 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?global_int@@3HA +// CHECK-DAG: Data 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ??_7Dyn@ns@@6B@ +// CHECK-DAG: Data 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?global_a@@3UA@@A +// CHECK-DAG: Data 0x{{[0-9a-f]+}} 0x{{0*[1-9a-f][0-9a-f]*}} 0x00000000 ?global_c@@3UC@?$B@_J@ns@@A diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 7db334c..dd1bbbd 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -1,9 +1,6 @@ # We need to include the llvm components we depend on manually, as liblldb does # not re-export those. set(LLVM_LINK_COMPONENTS Support) -set(LLVM_TARGET_DEFINITIONS Options.td) -tablegen(LLVM Options.inc -gen-opt-parser-defs) -add_public_tablegen_target(LLDBDAPOptionsTableGen) add_lldb_library(lldbDAP Breakpoint.cpp diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp index c5d5f2b..12d9e21 100644 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ b/lldb/tools/lldb-dap/EventHelper.cpp @@ -176,7 +176,7 @@ llvm::Error SendThreadStoppedEvent(DAP &dap, bool on_entry) { llvm::DenseSet<lldb::tid_t> old_thread_ids; old_thread_ids.swap(dap.thread_ids); - uint32_t stop_id = process.GetStopID(); + uint32_t stop_id = on_entry ? 0 : process.GetStopID(); const uint32_t num_threads = process.GetNumThreads(); // First make a pass through the threads to see if the focused thread diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 2780a5b..1a3a670 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -711,7 +711,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, break; } if (stop_id == 0) - body.try_emplace("reason", "entry"); + body["reason"] = "entry"; const lldb::tid_t tid = thread.GetThreadID(); body.try_emplace("threadId", (int64_t)tid); // If no description has been set, then set it to the default thread stopped diff --git a/lldb/tools/lldb-dap/tool/CMakeLists.txt b/lldb/tools/lldb-dap/tool/CMakeLists.txt index b39a4ed..5335d25 100644 --- a/lldb/tools/lldb-dap/tool/CMakeLists.txt +++ b/lldb/tools/lldb-dap/tool/CMakeLists.txt @@ -1,3 +1,7 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(LLDBDAPOptionsTableGen) + add_lldb_tool(lldb-dap lldb-dap.cpp diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/tool/Options.td index 5e9dd7a..5e9dd7a 100644 --- a/lldb/tools/lldb-dap/Options.td +++ b/lldb/tools/lldb-dap/tool/Options.td diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 1981e91..155fc74 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -52,6 +52,12 @@ protected: return ClangUtil::GetQualType( m_ast->GetBuiltinTypeByName(ConstString(name))); } + + CompilerType GetBuiltinTypeForDWARFEncodingAndBitSize( + llvm::StringRef type_name, uint32_t encoding, uint32_t bit_size) const { + return m_ast->GetBuiltinTypeForDWARFEncodingAndBitSize(type_name, encoding, + bit_size); + } }; TEST_F(TestTypeSystemClang, TestGetBasicTypeFromEnum) { @@ -238,6 +244,91 @@ TEST_F(TestTypeSystemClang, TestBuiltinTypeForEncodingAndBitSize) { VerifyEncodingAndBitSize(*m_ast, eEncodingIEEE754, 64); } +TEST_F(TestTypeSystemClang, TestGetBuiltinTypeForDWARFEncodingAndBitSize) { + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitIn", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "BitInt", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_signed_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(2)", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeName(), + "_BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeName(), + "_BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt(129)", llvm::dwarf::DW_ATE_signed, 129) + .GetTypeName(), + "_BitInt(129)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 129) + .GetTypeName(), + "_BitInt(129)"); + + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitIn", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned_char, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + EXPECT_FALSE(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_signed, 2) + .IsValid()); + + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(2)", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeName(), + "unsigned _BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeName(), + "unsigned _BitInt(2)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt(129)", llvm::dwarf::DW_ATE_unsigned, 129) + .GetTypeName(), + "unsigned _BitInt(129)"); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 129) + .GetTypeName(), + "unsigned _BitInt(129)"); +} + +TEST_F(TestTypeSystemClang, TestBitIntTypeInfo) { + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "_BitInt", llvm::dwarf::DW_ATE_signed, 2) + .GetTypeInfo(), + eTypeIsSigned | eTypeIsScalar | eTypeHasValue | eTypeIsInteger); + EXPECT_EQ(GetBuiltinTypeForDWARFEncodingAndBitSize( + "unsigned _BitInt", llvm::dwarf::DW_ATE_unsigned, 2) + .GetTypeInfo(), + eTypeIsScalar | eTypeHasValue | eTypeIsInteger); +} + TEST_F(TestTypeSystemClang, TestBuiltinTypeForEmptyTriple) { // Test that we can access type-info of builtin Clang AST // types without crashing even when the target triple is @@ -1123,6 +1214,30 @@ TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) { EXPECT_EQ(method_it->getParamDecl(1)->getDeclContext(), *method_it); } +TEST_F(TestTypeSystemClang, TestGetTypeInfo) { + // Tests TypeSystemClang::GetTypeInfo + + const ASTContext &ast = m_ast->getASTContext(); + + CompilerType complex_int = m_ast->GetType(ast.getComplexType(ast.IntTy)); + EXPECT_EQ(complex_int.GetTypeInfo(), + (eTypeIsInteger | eTypeIsComplex | eTypeIsBuiltIn | eTypeHasValue)); + + CompilerType complex_float = m_ast->GetType(ast.getComplexType(ast.FloatTy)); + EXPECT_EQ(complex_float.GetTypeInfo(), + (eTypeIsFloat | eTypeIsComplex | eTypeIsBuiltIn | eTypeHasValue)); + + CompilerType vector_of_int = + m_ast->GetType(ast.getVectorType(ast.IntTy, 1, VectorKind::Generic)); + EXPECT_EQ(vector_of_int.GetTypeInfo(), + (eTypeIsInteger | eTypeIsVector | eTypeHasChildren)); + + CompilerType vector_of_float = + m_ast->GetType(ast.getVectorType(ast.FloatTy, 1, VectorKind::Generic)); + EXPECT_EQ(vector_of_float.GetTypeInfo(), + (eTypeIsFloat | eTypeIsVector | eTypeHasChildren)); +} + TEST_F(TestTypeSystemClang, AsmLabel_CtorDtor) { // Tests TypeSystemClang::DeclGetMangledName for constructors/destructors // with and without AsmLabels. diff --git a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp index 064ed6d..cef3a25a 100644 --- a/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp @@ -1741,3 +1741,215 @@ DWARF: EXPECT_EQ(llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), 1U); } + +TEST_F(DWARFASTParserClangTests, TestBitIntParsing) { + // Tests that we correctly parse the DW_AT_base_type for a _BitInt. + // Older versions of Clang only emit the `_BitInt` string into the + // DW_AT_name (not including the bitsize). Make sure we understand + // those too. + + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_AARCH64 +DWARF: + debug_str: + - _BitInt(2) + - _BitInt + - unsigned _BitInt(2) + - unsigned _BitInt + debug_abbrev: + - ID: 0 + Table: + - Code: 0x1 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x2 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + - Attribute: DW_AT_bit_size + Form: DW_FORM_data1 + - Code: 0x3 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + + debug_info: + - Version: 5 + UnitType: DW_UT_compile + AddrSize: 8 + Entries: + +# DW_TAG_compile_unit +# DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) + + - AbbrCode: 0x1 + Values: + - Value: 0x04 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt(2)') + + - AbbrCode: 0x2 + Values: + - Value: 0x0 + - Value: 0x05 + - Value: 0x01 + - Value: 0x02 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt') + + - AbbrCode: 0x2 + Values: + - Value: 0x0b + - Value: 0x05 + - Value: 0x08 + - Value: 0x34 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt(2)') + + - AbbrCode: 0x2 + Values: + - Value: 0x13 + - Value: 0x07 + - Value: 0x01 + - Value: 0x02 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('unsigned _BitInt') + + - AbbrCode: 0x2 + Values: + - Value: 0x27 + - Value: 0x07 + - Value: 0x08 + - Value: 0x34 + +# DW_TAG_base_type +# DW_AT_name [DW_FORM_strp] ('_BitInt') + + - AbbrCode: 0x3 + Values: + - Value: 0x0b + - Value: 0x05 + - Value: 0x08 +... + +)"; + + YAMLModuleTester t(yamldata); + + DWARFUnit *unit = t.GetDwarfUnit(); + ASSERT_NE(unit, nullptr); + const DWARFDebugInfoEntry *cu_entry = unit->DIE().GetDIE(); + ASSERT_EQ(cu_entry->Tag(), DW_TAG_compile_unit); + ASSERT_EQ(unit->GetDWARFLanguageType(), DW_LANG_C_plus_plus); + DWARFDIE cu_die(unit, cu_entry); + + auto holder = std::make_unique<clang_utils::TypeSystemClangHolder>("ast"); + auto &ast_ctx = *holder->GetAST(); + DWARFASTParserClangStub ast_parser(ast_ctx); + + auto type_die = cu_die.GetFirstChild(); + ASSERT_TRUE(type_die.IsValid()); + + { + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 1U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt(2)"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(2)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(52)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 1U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingUint); + EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt(2)"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), + "unsigned _BitInt(2)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingUint); + EXPECT_EQ(type_sp->GetName(), "unsigned _BitInt"); + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), + "unsigned _BitInt(52)"); + } + + { + type_die = type_die.GetSibling(); + SymbolContext sc; + auto type_sp = ast_parser.ParseTypeFromDWARF(sc, type_die, + /*type_is_new_ptr=*/nullptr); + ASSERT_NE(type_sp, nullptr); + + EXPECT_EQ( + llvm::expectedToOptional(type_sp->GetByteSize(nullptr)).value_or(0), + 8U); + EXPECT_EQ(type_sp->GetEncoding(), lldb::eEncodingSint); + EXPECT_EQ(type_sp->GetName(), "_BitInt"); + + // Older versions of Clang didn't emit a DW_AT_bit_size for _BitInt. In + // those cases we would format the CompilerType name using the byte-size. + EXPECT_EQ(type_sp->GetForwardCompilerType().GetTypeName(), "_BitInt(64)"); + } +} |
