jasonmolenda updated this revision to Diff 360717.
jasonmolenda added a comment.
Update patch to address Jonas' suggestion of not duplicating the code to write
the LC_NOTE load command & payloads (I was annoyed by this too but didn't deal
with it in my first pass). Also add a test, although it only is really tested
on an arm64e testsuite run where the compiler is doing PAC auth on return
addresses.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D106348/new/
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
lldb/test/API/macosx/lc-note/addrable-bits/Makefile
lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py
lldb/test/API/macosx/lc-note/addrable-bits/main.c
Index: lldb/test/API/macosx/lc-note/addrable-bits/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/lc-note/addrable-bits/main.c
@@ -0,0 +1,12 @@
+int pat (int in) {
+ return in + 5; // break here
+}
+
+int tat (int in) { return pat(in + 10); }
+
+int mat (int in) { return tat(in + 15); }
+
+int main() {
+ int (*matp)(int) = mat;
+ return matp(10);
+}
Index: lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py
@@ -0,0 +1,59 @@
+"""Test that corefiles with LC_NOTE "addrable bits" load command, creating and reading."""
+
+
+
+import os
+import re
+import subprocess
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestAddrableBitsCorefile(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def initial_setup(self):
+ self.build()
+ self.exe = self.getBuildArtifact("a.out")
+ self.corefile = self.getBuildArtifact("corefile")
+
+ @skipIf(archs=no_match(['arm64e']))
+ @skipUnlessDarwin
+ def test_lc_note_addrable_bits(self):
+ self.initial_setup()
+
+ self.target = self.dbg.CreateTarget(self.exe)
+ err = lldb.SBError()
+ (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, "break here",
+ lldb.SBFileSpec('main.c'))
+ self.assertEqual(process.IsValid(), True)
+
+ found_main = False
+ for f in thread.frames:
+ if f.GetFunctionName() == "main":
+ found_main = True
+ self.assertTrue(found_main)
+
+ cmdinterp = self.dbg.GetCommandInterpreter()
+ res = lldb.SBCommandReturnObject()
+ cmdinterp.HandleCommand("process save-core %s" % self.corefile, res)
+ self.assertTrue(res.Succeeded(), True)
+ process.Kill()
+ self.dbg.DeleteTarget(target)
+
+ target = self.dbg.CreateTarget('')
+ process = target.LoadCore(self.corefile)
+ self.assertTrue(process.IsValid(), True)
+ thread = process.GetSelectedThread()
+
+ found_main = False
+ for f in thread.frames:
+ if f.GetFunctionName() == "main":
+ found_main = True
+ self.assertTrue(found_main)
+
Index: lldb/test/API/macosx/lc-note/addrable-bits/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/lc-note/addrable-bits/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
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
@@ -15,6 +15,7 @@
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/RangeMap.h"
+#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/UUID.h"
// This class needs to be hidden as eventually belongs in a plugin that
@@ -113,6 +114,8 @@
std::string GetIdentifierString() override;
+ lldb::addr_t GetAddressMask() override;
+
bool GetCorefileMainBinaryInfo(lldb::addr_t &address,
lldb_private::UUID &uuid,
ObjectFile::BinaryType &type) override;
@@ -225,6 +228,15 @@
segment_load_addresses;
};
+ struct LCNoteEntry {
+ LCNoteEntry(uint32_t addr_byte_size, lldb::ByteOrder byte_order)
+ : payload(lldb_private::Stream::eBinary, addr_byte_size, byte_order) {}
+
+ std::string name;
+ lldb::addr_t payload_file_offset = 0;
+ lldb_private::StreamString payload;
+ };
+
struct MachOCorefileAllImageInfos {
std::vector<MachOCorefileImageEntry> all_image_infos;
bool IsValid() { return all_image_infos.size() > 0; }
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);
@@ -6673,28 +6723,48 @@
addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds;
file_offset = llvm::alignTo(file_offset, 16);
+ std::vector<std::unique_ptr<LCNoteEntry>> lc_notes;
+
+ // Add "addrable bits" LC_NOTE when an address mask is available
+ if (address_mask != 0) {
+ std::unique_ptr<LCNoteEntry> addrable_bits_lcnote_up(
+ new LCNoteEntry(addr_byte_size, byte_order));
+ addrable_bits_lcnote_up->name = "addrable bits";
+ addrable_bits_lcnote_up->payload_file_offset = file_offset;
+ int bits = std::bitset<64>(~address_mask).count();
+ addrable_bits_lcnote_up->payload.PutHex32(3); // version
+ addrable_bits_lcnote_up->payload.PutHex32(
+ bits); // # of bits used for addressing
+ addrable_bits_lcnote_up->payload.PutHex64(0); // unused
+
+ file_offset += addrable_bits_lcnote_up->payload.GetSize();
+
+ lc_notes.push_back(std::move(addrable_bits_lcnote_up));
+ }
- // Create the "all image infos" LC_NOTE payload
- StreamString all_image_infos_payload(Stream::eBinary, addr_byte_size,
- byte_order);
- offset_t all_image_infos_payload_start = file_offset;
- file_offset = CreateAllImageInfosPayload(process_sp, file_offset,
- all_image_infos_payload);
-
- // Add the "all image infos" LC_NOTE load command
- llvm::MachO::note_command all_image_info_note = {
- LC_NOTE, /* uint32_t cmd */
- sizeof(llvm::MachO::note_command), /* uint32_t cmdsize */
- "all image infos", /* char data_owner[16] */
- all_image_infos_payload_start, /* uint64_t offset */
- file_offset - all_image_infos_payload_start /* uint64_t size */
- };
- buffer.PutHex32(all_image_info_note.cmd);
- buffer.PutHex32(all_image_info_note.cmdsize);
- buffer.PutRawBytes(all_image_info_note.data_owner,
- sizeof(all_image_info_note.data_owner));
- buffer.PutHex64(all_image_info_note.offset);
- buffer.PutHex64(all_image_info_note.size);
+ // Add "all image infos" LC_NOTE
+ std::unique_ptr<LCNoteEntry> all_image_infos_lcnote_up(
+ new LCNoteEntry(addr_byte_size, byte_order));
+ all_image_infos_lcnote_up->name = "all image infos";
+ all_image_infos_lcnote_up->payload_file_offset = file_offset;
+ file_offset = CreateAllImageInfosPayload(
+ process_sp, file_offset, all_image_infos_lcnote_up->payload);
+ lc_notes.push_back(std::move(all_image_infos_lcnote_up));
+
+ // Add LC_NOTE load commands
+ for (auto &lcnote : lc_notes) {
+ // Add the LC_NOTE load command to the file.
+ buffer.PutHex32(LC_NOTE);
+ buffer.PutHex32(sizeof(llvm::MachO::note_command));
+ char namebuf[16];
+ memset(namebuf, 0, sizeof(namebuf));
+ // this is the uncommon case where strncpy is exactly
+ // the right one, doesn't need to be nul terminated.
+ strncpy(namebuf, lcnote->name.c_str(), sizeof(namebuf));
+ buffer.PutRawBytes(namebuf, sizeof(namebuf));
+ buffer.PutHex64(lcnote->payload_file_offset);
+ buffer.PutHex64(lcnote->payload.GetSize());
+ }
// Align to 4096-byte page boundary for the LC_SEGMENTs.
file_offset = llvm::alignTo(file_offset, 4096);
@@ -6749,19 +6819,21 @@
core_file.get()->Write(buffer.GetString().data(), bytes_written);
if (error.Success()) {
- if (core_file.get()->SeekFromStart(all_image_info_note.offset) ==
- -1) {
- error.SetErrorStringWithFormat(
- "Unable to seek to corefile pos to write all iamge infos");
- return false;
+ for (auto &lcnote : lc_notes) {
+ if (core_file.get()->SeekFromStart(lcnote->payload_file_offset) ==
+ -1) {
+ error.SetErrorStringWithFormat("Unable to seek to corefile pos "
+ "to write '%s' LC_NOTE payload",
+ lcnote->name.c_str());
+ return false;
+ }
+ bytes_written = lcnote->payload.GetSize();
+ error = core_file.get()->Write(lcnote->payload.GetData(),
+ bytes_written);
+ if (!error.Success())
+ return false;
}
- bytes_written = all_image_infos_payload.GetString().size();
- error = core_file.get()->Write(
- all_image_infos_payload.GetString().data(), bytes_written);
- if (!error.Success())
- return false;
-
// Now write the file data for all memory segments in the process
for (const auto &segment : segment_load_commands) {
if (core_file.get()->SeekFromStart(segment.fileoff) == -1) {
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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits