jasonmolenda created this revision. jasonmolenda added a reviewer: JDevlieghere. jasonmolenda added a project: LLDB. Herald added a subscriber: kristof.beyls. jasonmolenda requested review of this revision.
On systems where we have an address mask, add support to process save-core to note the number of bits used for addressing in the corefile in an LC_NOTE, and look for that value in a corefile and set the mask in the Process. In a live debug session on Apple Silicon using arm64e, debugserver reports the number of bits used for addressing. Corefiles of those same processes don't currently record this information any place, making them hard to use. This is a simple patch to add the LC_NOTE and read it back in again, nothing fancy. I added a couple of comments on the masks to note that the mask uses 1 bits to indicate bits not used in addressing, open to disagreements about this but it always seemed backwards to me (I know we're following what the Linux kernel provides) and I will confuse myself if I'm not careful. Basically, leaving notes so Future Jason doesn't have to puzzle over the right answer quite so long, because I'm sure I'll forget this again. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D106348 Files: lldb/include/lldb/Symbol/ObjectFile.h lldb/include/lldb/Target/Process.h lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
Index: lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp =================================================================== --- lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -541,6 +541,11 @@ if (arch.IsValid()) GetTarget().SetArchitecture(arch); + addr_t address_mask = core_objfile->GetAddressMask(); + if (address_mask != 0) { + SetCodeAddressMask(address_mask); + SetDataAddressMask(address_mask); + } return error; } Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h =================================================================== --- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -113,6 +113,8 @@ std::string GetIdentifierString() override; + lldb::addr_t GetAddressMask() override; + bool GetCorefileMainBinaryInfo(lldb::addr_t &address, lldb_private::UUID &uuid, ObjectFile::BinaryType &type) override; Index: lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -62,6 +62,7 @@ #include <uuid/uuid.h> #endif +#include <bitset> #include <memory> #if LLVM_SUPPORT_XCODE_SIGNPOSTS @@ -5571,6 +5572,46 @@ return result; } +addr_t ObjectFileMachO::GetAddressMask() { + addr_t mask = 0; + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + llvm::MachO::load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) + break; + if (lc.cmd == LC_NOTE) { + char data_owner[17]; + m_data.CopyData(offset, 16, data_owner); + data_owner[16] = '\0'; + offset += 16; + uint64_t fileoff = m_data.GetU64_unchecked(&offset); + + // "addrable bits" has a uint32_t version and a uint32_t + // number of bits used in addressing. + if (strcmp("addrable bits", data_owner) == 0) { + offset = fileoff; + uint32_t version; + if (m_data.GetU32(&offset, &version, 1) != nullptr) { + if (version == 3) { + uint32_t num_addr_bits = m_data.GetU32_unchecked(&offset); + if (num_addr_bits != 0) { + mask = ~((1ULL << num_addr_bits) - 1); + } + break; + } + } + } + } + offset = cmd_offset + lc.cmdsize; + } + } + return mask; +} + bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid, ObjectFile::BinaryType &type) { address = LLDB_INVALID_ADDRESS; @@ -6652,6 +6693,15 @@ mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize(); } + // Bits will be set to indicate which bits are NOT used in + // addressing in this process or 0 for unknown. + uint64_t address_mask = process_sp->GetCodeAddressMask(); + if (address_mask != 0) { + // LC_NOTE "addrable bits" + mach_header.ncmds++; + mach_header.sizeofcmds += sizeof(llvm::MachO::note_command); + } + // LC_NOTE "all image infos" mach_header.ncmds++; mach_header.sizeofcmds += sizeof(llvm::MachO::note_command); @@ -6674,6 +6724,34 @@ file_offset = llvm::alignTo(file_offset, 16); + StreamString addrable_bits_payload(Stream::eBinary, addr_byte_size, + byte_order); + llvm::MachO::note_command addrable_bits_note; + if (address_mask != 0) { + // Create the "addrable bits" LC_NOTE payload + offset_t addrable_bits_payload_start = file_offset; + int bits = std::bitset<64>(~address_mask).count(); + addrable_bits_payload.PutHex32(3); // version + addrable_bits_payload.PutHex32(bits); // # of bits used for addressing + addrable_bits_payload.PutHex64(0); // unused + + file_offset += addrable_bits_payload.GetSize(); + + // Add the "all image infos" LC_NOTE load command + addrable_bits_note.cmd = LC_NOTE; + addrable_bits_note.cmdsize = sizeof(llvm::MachO::note_command); + strcpy(addrable_bits_note.data_owner, "addrable bits"); + addrable_bits_note.offset = addrable_bits_payload_start; + addrable_bits_note.size = addrable_bits_payload.GetSize(); + + buffer.PutHex32(addrable_bits_note.cmd); + buffer.PutHex32(addrable_bits_note.cmdsize); + buffer.PutRawBytes(addrable_bits_note.data_owner, + sizeof(addrable_bits_note.data_owner)); + buffer.PutHex64(addrable_bits_note.offset); + buffer.PutHex64(addrable_bits_note.size); + } + // Create the "all image infos" LC_NOTE payload StreamString all_image_infos_payload(Stream::eBinary, addr_byte_size, byte_order); @@ -6749,16 +6827,32 @@ core_file.get()->Write(buffer.GetString().data(), bytes_written); if (error.Success()) { + if (address_mask != 0) { + + if (core_file.get()->SeekFromStart(addrable_bits_note.offset) == + -1) { + error.SetErrorStringWithFormat( + "Unable to seek to corefile pos to write addressable bits"); + return false; + } + + bytes_written = addrable_bits_payload.GetSize(); + error = core_file.get()->Write(addrable_bits_payload.GetData(), + bytes_written); + if (!error.Success()) + return false; + } + if (core_file.get()->SeekFromStart(all_image_info_note.offset) == -1) { error.SetErrorStringWithFormat( - "Unable to seek to corefile pos to write all iamge infos"); + "Unable to seek to corefile pos to write all image infos"); return false; } - bytes_written = all_image_infos_payload.GetString().size(); - error = core_file.get()->Write( - all_image_infos_payload.GetString().data(), bytes_written); + bytes_written = all_image_infos_payload.GetSize(); + error = core_file.get()->Write(all_image_infos_payload.GetData(), + bytes_written); if (!error.Success()) return false; Index: lldb/include/lldb/Target/Process.h =================================================================== --- lldb/include/lldb/Target/Process.h +++ lldb/include/lldb/Target/Process.h @@ -2899,7 +2899,8 @@ std::atomic<bool> m_finalizing; /// Mask for code an data addresses. The default value (0) means no mask is - /// set. + /// set. The bits set to 1 indicate bits that are NOT significant for + /// addressing. /// @{ lldb::addr_t m_code_address_mask = 0; lldb::addr_t m_data_address_mask = 0; Index: lldb/include/lldb/Symbol/ObjectFile.h =================================================================== --- lldb/include/lldb/Symbol/ObjectFile.h +++ lldb/include/lldb/Symbol/ObjectFile.h @@ -495,6 +495,16 @@ return std::string(); } + /// Some object files may have the number of bits used for addressing + /// embedded in them, e.g. a Mach-O core file using an LC_NOTE. These + /// object files can return the address mask that should be used in + /// the Process. + /// \return + /// The mask will have bits set which aren't used for addressing -- + /// typically, the high bits. + /// Zero is returned when no address bits mask is available. + virtual lldb::addr_t GetAddressMask() { return 0; } + /// When the ObjectFile is a core file, lldb needs to locate the "binary" in /// the core file. lldb can iterate over the pages looking for a valid /// binary, but some core files may have metadata describing where the main
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits