diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/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 diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2899,7 +2899,8 @@ std::atomic 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; diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/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; diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -62,6 +62,7 @@ #include #endif +#include #include #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 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; diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp --- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/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; }