[Lldb-commits] [lldb] 682532c - Support v2 of 'main bin spec' Mach-O LC_NOTE in corefiles
Jason Molenda via lldb-commits
lldb-commits at lists.llvm.org
Wed Dec 22 00:07:08 PST 2021
Author: Jason Molenda
Date: 2021-12-22T00:02:27-08:00
New Revision: 682532ca575b8b6c4d3e2104a7526743ff9446a9
URL: https://github.com/llvm/llvm-project/commit/682532ca575b8b6c4d3e2104a7526743ff9446a9
DIFF: https://github.com/llvm/llvm-project/commit/682532ca575b8b6c4d3e2104a7526743ff9446a9.diff
LOG: Support v2 of 'main bin spec' Mach-O LC_NOTE in corefiles
Version 2 of 'main bin spec' LC_NOTE allows for the specification
of a slide of where the binary is loaded in the corefile virtual
address space. It also adds a (currently unused) platform field
for the main binary.
Some corefile creators will only have a UUID and an offset to be
applied to the binary.
Changed TestFirmwareCorefiles.py to test this new form of
'main bin spec' with a slide, and also to run on both x86_64
and arm64 macOS systems.
Differential Revision: https://reviews.llvm.org/D116094
rdar://85938455
Added:
Modified:
lldb/include/lldb/Symbol/ObjectFile.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/firmware-corefile/TestFirmwareCorefiles.py
lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index bfc5d382dbf98..8bf047cd45141 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -527,11 +527,15 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
/// binary is exactly which removes ambiguity when there are multiple
/// binaries present in the captured memory pages.
///
- /// \param[out] address
- /// If the address of the binary is specified, this will be set.
- /// This is an address is the virtual address space of the core file
- /// memory segments; it is not an offset into the object file.
- /// If no address is available, will be set to LLDB_INVALID_ADDRESS.
+ /// \param[out] value
+ /// The address or offset (slide) where the binary is loaded in memory.
+ /// LLDB_INVALID_ADDRESS for unspecified. If an offset is given,
+ /// this offset should be added to the binary's file address to get
+ /// the load address.
+ ///
+ /// \param[out] value_is_offset
+ /// Specifies if \b value is a load address, or an offset to calculate
+ /// the load address.
///
/// \param[out] uuid
/// If the uuid of the binary is specified, this will be set.
@@ -543,9 +547,11 @@ class ObjectFile : public std::enable_shared_from_this<ObjectFile>,
///
/// \return
/// Returns true if either address or uuid has been set.
- virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &address, UUID &uuid,
+ virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &value,
+ bool &value_is_offset, UUID &uuid,
ObjectFile::BinaryType &type) {
- address = LLDB_INVALID_ADDRESS;
+ value = LLDB_INVALID_ADDRESS;
+ value_is_offset = false;
uuid.Clear();
return false;
}
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index e0087dbd4941e..7668b68650b4d 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5620,10 +5620,15 @@ addr_t ObjectFileMachO::GetAddressMask() {
return mask;
}
-bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid,
+bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
+ bool &value_is_offset,
+ UUID &uuid,
ObjectFile::BinaryType &type) {
- address = LLDB_INVALID_ADDRESS;
+ value = LLDB_INVALID_ADDRESS;
+ value_is_offset = false;
uuid.Clear();
+ uint32_t log2_pagesize = 0; // not currently passed up to caller
+ uint32_t platform = 0; // not currently passed up to caller
ModuleSP module_sp(GetModule());
if (module_sp) {
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
@@ -5641,6 +5646,26 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid,
uint64_t fileoff = m_data.GetU64_unchecked(&offset);
uint64_t size = m_data.GetU64_unchecked(&offset);
+ // struct main_bin_spec
+ // {
+ // uint32_t version; // currently 2
+ // uint32_t type; // 0 == unspecified, 1 == kernel,
+ // // 2 == user process,
+ // // 3 == standalone binary
+ // uint64_t address; // UINT64_MAX if address not specified
+ // uint64_t slide; // slide, UINT64_MAX if unspecified
+ // // 0 if no slide needs to be applied to
+ // // file address
+ // uuid_t uuid; // all zero's if uuid not specified
+ // uint32_t log2_pagesize; // process page size in log base 2,
+ // // e.g. 4k pages are 12.
+ // // 0 for unspecified
+ // uint32_t platform; // The Mach-O platform for this corefile.
+ // // 0 for unspecified.
+ // // The values are defined in
+ // // <mach-o/loader.h>, PLATFORM_*.
+ // } __attribute((packed));
+
// "main bin spec" (main binary specification) data payload is
// formatted:
// uint32_t version [currently 1]
@@ -5656,14 +5681,25 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid,
if (strcmp("main bin spec", data_owner) == 0 && size >= 32) {
offset = fileoff;
uint32_t version;
- if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) {
+ if (m_data.GetU32(&offset, &version, 1) != nullptr && version <= 2) {
uint32_t binspec_type = 0;
uuid_t raw_uuid;
memset(raw_uuid, 0, sizeof(uuid_t));
- if (m_data.GetU32(&offset, &binspec_type, 1) &&
- m_data.GetU64(&offset, &address, 1) &&
- m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
+ if (!m_data.GetU32(&offset, &binspec_type, 1))
+ return false;
+ if (!m_data.GetU64(&offset, &value, 1))
+ return false;
+ uint64_t slide = LLDB_INVALID_ADDRESS;
+ if (version > 1 && !m_data.GetU64(&offset, &slide, 1))
+ return false;
+ if (value == LLDB_INVALID_ADDRESS &&
+ slide != LLDB_INVALID_ADDRESS) {
+ value = slide;
+ value_is_offset = true;
+ }
+
+ if (m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t));
// convert the "main bin spec" type into our
// ObjectFile::BinaryType enum
@@ -5681,6 +5717,10 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid,
type = eBinaryTypeStandalone;
break;
}
+ if (!m_data.GetU32(&offset, &log2_pagesize, 1))
+ return false;
+ if (version > 1 && !m_data.GetU32(&offset, &platform, 1))
+ return false;
return true;
}
}
@@ -7006,7 +7046,17 @@ bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) {
ModuleSpec module_spec;
module_spec.GetUUID() = image.uuid;
- module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
+ if (image.filename.empty()) {
+ char namebuf[80];
+ if (image.load_address != LLDB_INVALID_ADDRESS)
+ snprintf(namebuf, sizeof(namebuf), "mem-image-0x%" PRIx64,
+ image.load_address);
+ else
+ snprintf(namebuf, sizeof(namebuf), "mem-image+0x%" PRIx64, image.slide);
+ module_spec.GetFileSpec() = FileSpec(namebuf);
+ } else {
+ module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
+ }
if (image.currently_executing) {
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
index 084b0ac110ba1..c666ef32b85e7 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
@@ -120,7 +120,7 @@ class ObjectFileMachO : public lldb_private::ObjectFile {
lldb::addr_t GetAddressMask() override;
- bool GetCorefileMainBinaryInfo(lldb::addr_t &address,
+ bool GetCorefileMainBinaryInfo(lldb::addr_t &value, bool &value_is_offset,
lldb_private::UUID &uuid,
ObjectFile::BinaryType &type) override;
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 6aed04565eb01..4b3e244dcb23f 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -184,7 +184,8 @@ bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) {
// Try to load a file with that UUID into lldb, and if we have a load
// address, set it correctly. Else assume that the binary was loaded
// with no slide.
-static bool load_standalone_binary(UUID uuid, addr_t addr, Target &target) {
+static bool load_standalone_binary(UUID uuid, addr_t value,
+ bool value_is_offset, Target &target) {
if (uuid.IsValid()) {
ModuleSpec module_spec;
module_spec.GetUUID() = uuid;
@@ -205,18 +206,34 @@ static bool load_standalone_binary(UUID uuid, addr_t addr, Target &target) {
}
}
- if (module_sp.get() && module_sp->GetObjectFile()) {
+ // If we couldn't find the binary anywhere else, as a last resort,
+ // read it out of memory in the corefile.
+ if (!module_sp.get() && value != LLDB_INVALID_ADDRESS && !value_is_offset) {
+ char namebuf[80];
+ snprintf(namebuf, sizeof(namebuf), "mem-image-0x%" PRIx64, value);
+ module_sp =
+ target.GetProcessSP()->ReadModuleFromMemory(FileSpec(namebuf), value);
+ }
+
+ if (module_sp.get()) {
target.SetArchitecture(module_sp->GetObjectFile()->GetArchitecture());
target.GetImages().AppendIfNeeded(module_sp, false);
- Address base_addr = module_sp->GetObjectFile()->GetBaseAddress();
- addr_t slide = 0;
- if (addr != LLDB_INVALID_ADDRESS && base_addr.IsValid()) {
- addr_t file_load_addr = base_addr.GetFileAddress();
- slide = addr - file_load_addr;
- }
bool changed = false;
- module_sp->SetLoadAddress(target, slide, true, changed);
+ if (module_sp->GetObjectFile()) {
+ if (value != LLDB_INVALID_ADDRESS) {
+ module_sp->SetLoadAddress(target, value, value_is_offset, changed);
+ } else {
+ // No address/offset/slide, load the binary at file address,
+ // offset 0.
+ const bool value_is_slide = true;
+ module_sp->SetLoadAddress(target, 0, value_is_slide, changed);
+ }
+ } else {
+ // In-memory image, load at its true address, offset 0.
+ const bool value_is_slide = true;
+ module_sp->SetLoadAddress(target, 0, value_is_slide, changed);
+ }
ModuleList added_module;
added_module.Append(module_sp, false);
@@ -316,33 +333,38 @@ Status ProcessMachCore::DoLoadCore() {
bool found_main_binary_definitively = false;
- addr_t objfile_binary_addr;
+ addr_t objfile_binary_value;
+ bool objfile_binary_value_is_offset;
UUID objfile_binary_uuid;
ObjectFile::BinaryType type;
- if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr,
+ if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_value,
+ objfile_binary_value_is_offset,
objfile_binary_uuid, type)) {
if (log) {
log->Printf(
"ProcessMachCore::DoLoadCore: using binary hint from 'main bin spec' "
- "LC_NOTE with UUID %s address 0x%" PRIx64 " and type %d",
- objfile_binary_uuid.GetAsString().c_str(), objfile_binary_addr, type);
+ "LC_NOTE with UUID %s value 0x%" PRIx64
+ " value is offset %d and type %d",
+ objfile_binary_uuid.GetAsString().c_str(), objfile_binary_value,
+ objfile_binary_value_is_offset, type);
}
- if (objfile_binary_addr != LLDB_INVALID_ADDRESS) {
+ if (objfile_binary_value != LLDB_INVALID_ADDRESS &&
+ !objfile_binary_value_is_offset) {
if (type == ObjectFile::eBinaryTypeUser) {
- m_dyld_addr = objfile_binary_addr;
+ m_dyld_addr = objfile_binary_value;
m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
found_main_binary_definitively = true;
}
if (type == ObjectFile::eBinaryTypeKernel) {
- m_mach_kernel_addr = objfile_binary_addr;
+ m_mach_kernel_addr = objfile_binary_value;
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
found_main_binary_definitively = true;
}
}
if (!found_main_binary_definitively) {
// ObjectFile::eBinaryTypeStandalone, undeclared types
- if (load_standalone_binary(objfile_binary_uuid, objfile_binary_addr,
- GetTarget())) {
+ if (load_standalone_binary(objfile_binary_uuid, objfile_binary_value,
+ objfile_binary_value_is_offset, GetTarget())) {
found_main_binary_definitively = true;
m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
}
@@ -388,17 +410,21 @@ Status ProcessMachCore::DoLoadCore() {
m_mach_kernel_addr = ident_binary_addr;
found_main_binary_definitively = true;
} else if (ident_uuid.IsValid()) {
- if (load_standalone_binary(ident_uuid, ident_binary_addr, GetTarget())) {
+ // We have no address specified, only a UUID. Load it at the file
+ // address.
+ const bool value_is_offset = false;
+ if (load_standalone_binary(ident_uuid, ident_binary_addr, value_is_offset,
+ GetTarget())) {
found_main_binary_definitively = true;
m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
}
}
}
+ bool did_load_extra_binaries = core_objfile->LoadCoreFileImages(*this);
// If we have a "all image infos" LC_NOTE, try to load all of the
// binaries listed, and set their Section load addresses in the Target.
- if (found_main_binary_definitively == false &&
- core_objfile->LoadCoreFileImages(*this)) {
+ if (found_main_binary_definitively == false && did_load_extra_binaries) {
m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic();
found_main_binary_definitively = true;
}
diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
index a28b01bb1789e..6600c6344c7dc 100644
--- a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
+++ b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
@@ -16,26 +16,174 @@ class TestFirmwareCorefiles(TestBase):
mydir = TestBase.compute_mydir(__file__)
- def initial_setup(self):
+ @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+ @skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e', 'aarch64']))
+ @skipIfRemote
+ @skipUnlessDarwin
+ def test_lc_note_version_string(self):
+ self.build()
+ aout_exe_basename = "a.out"
+ aout_exe = self.getBuildArtifact(aout_exe_basename)
+ verstr_corefile = self.getBuildArtifact("verstr.core")
+ verstr_corefile_addr = self.getBuildArtifact("verstr-addr.core")
+ create_corefile = self.getBuildArtifact("create-empty-corefile")
+ slide = 0x70000000000
+ call(create_corefile + " version-string " + verstr_corefile + " " + aout_exe + " 0xffffffffffffffff 0xffffffffffffffff", shell=True)
+ call(create_corefile + " version-string " + verstr_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True)
+
+ if self.TraceOn():
+ self.runCmd("log enable lldb dyld host")
+ self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
+
+ # Register the a.out binary with this UUID in lldb's global module
+ # cache, then throw the Target away.
+ target = self.dbg.CreateTarget(aout_exe)
+ self.dbg.DeleteTarget(target)
+
+ # First, try the "kern ver str" corefile
+ target = self.dbg.CreateTarget('')
+ err = lldb.SBError()
+ if self.TraceOn():
+ self.runCmd("script print('loading corefile %s')" % verstr_corefile)
+ process = target.LoadCore(verstr_corefile)
+ self.assertEqual(process.IsValid(), True)
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("target mod dump sections")
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
+ self.dbg.DeleteTarget(target)
+
+ # Second, try the "kern ver str" corefile where it loads at an address
+ target = self.dbg.CreateTarget('')
+ err = lldb.SBError()
+ if self.TraceOn():
+ self.runCmd("script print('loading corefile %s')" % verstr_corefile_addr)
+ process = target.LoadCore(verstr_corefile_addr)
+ self.assertEqual(process.IsValid(), True)
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("target mod dump sections")
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
+ main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
+ main_addr = main_sym.GetStartAddress()
+ self.assertGreater(main_addr.GetLoadAddress(target), slide)
+ self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS)
+ self.dbg.DeleteTarget(target)
+
+ @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+ @skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e', 'aarch64']))
+ @skipIfRemote
+ @skipUnlessDarwin
+ def test_lc_note_main_bin_spec(self):
+ self.build()
+ aout_exe_basename = "a.out"
+ aout_exe = self.getBuildArtifact(aout_exe_basename)
+ create_corefile = self.getBuildArtifact("create-empty-corefile")
+ binspec_corefile = self.getBuildArtifact("binspec.core")
+ binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core")
+ binspec_corefile_slideonly = self.getBuildArtifact("binspec-addr-slideonly.core")
+
+ slide = 0x70000000000
+
+ ### Create our corefile
+ # 0xffffffffffffffff means load address unknown
+ call(create_corefile + " main-bin-spec " + binspec_corefile + " " + aout_exe + " 0xffffffffffffffff 0xffffffffffffffff", shell=True)
+ call(create_corefile + " main-bin-spec " + binspec_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True)
+ call(create_corefile + " main-bin-spec " + binspec_corefile_slideonly + " " + aout_exe + " 0xffffffffffffffff" + (" 0x%x" % slide), shell=True)
+
+ if self.TraceOn():
+ self.runCmd("log enable lldb dyld host")
+ self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
+
+ # Register the a.out binary with this UUID in lldb's global module
+ # cache, then throw the Target away.
+ target = self.dbg.CreateTarget(aout_exe)
+ self.dbg.DeleteTarget(target)
+
+ # First, try the "main bin spec" corefile
+ target = self.dbg.CreateTarget('')
+ if self.TraceOn():
+ self.runCmd("script print('loading corefile %s')" % binspec_corefile)
+ process = target.LoadCore(binspec_corefile)
+ self.assertEqual(process.IsValid(), True)
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("target mod dump sections")
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
+ self.dbg.DeleteTarget(target)
+
+ # Second, try the "main bin spec" corefile where it loads at an address
+ target = self.dbg.CreateTarget('')
+ if self.TraceOn():
+ self.runCmd("script print('loading corefile %s')" % binspec_corefile_addr)
+ process = target.LoadCore(binspec_corefile_addr)
+ self.assertEqual(process.IsValid(), True)
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("target mod dump sections")
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
+ main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
+ main_addr = main_sym.GetStartAddress()
+ self.assertGreater(main_addr.GetLoadAddress(target), slide)
+ self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS)
+ self.dbg.DeleteTarget(target)
+
+ # Third, try the "main bin spec" corefile where it loads at a slide
+ target = self.dbg.CreateTarget('')
+ if self.TraceOn():
+ self.runCmd("script print('loading corefile %s')" % binspec_corefile_slideonly)
+ process = target.LoadCore(binspec_corefile_slideonly)
+ self.assertEqual(process.IsValid(), True)
+ if self.TraceOn():
+ self.runCmd("image list")
+ self.runCmd("target mod dump sections")
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
+ main_sym = target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
+ main_addr = main_sym.GetStartAddress()
+ self.assertGreater(main_addr.GetLoadAddress(target), slide)
+ self.assertNotEqual(main_addr.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS)
+ self.dbg.DeleteTarget(target)
+
+ @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
+ @skipIf(archs=no_match(['x86_64', 'arm64', 'arm64e', 'aarch64']))
+ @skipIfRemote
+ @skipUnlessDarwin
+ def test_lc_note_main_bin_spec_os_plugin(self):
+
self.build()
- self.aout_exe = self.getBuildArtifact("a.out")
- self.aout_exe_basename = "a.out"
- self.create_corefile = self.getBuildArtifact("create-empty-corefile")
- self.dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")
- self.verstr_corefile = self.getBuildArtifact("verstr.core")
- self.verstr_corefile_addr = self.getBuildArtifact("verstr-addr.core")
- self.binspec_corefile = self.getBuildArtifact("binspec.core")
- self.binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core")
+ aout_exe = self.getBuildArtifact("a.out")
+ aout_exe_basename = "a.out"
+ create_corefile = self.getBuildArtifact("create-empty-corefile")
+ binspec_corefile_addr = self.getBuildArtifact("binspec-addr.core")
+
+ slide = 0x70000000000
+
+ ### Create our corefile
+ # 0xffffffffffffffff means load address unknown
+ call(create_corefile + " main-bin-spec " + binspec_corefile_addr + " " + aout_exe + (" 0x%x" % slide) + " 0xffffffffffffffff", shell=True)
## We can hook in our dsym-for-uuid shell script to lldb with this env
## var instead of requiring a defaults write.
- os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = self.dsym_for_uuid
+ dsym_for_uuid = self.getBuildArtifact("dsym-for-uuid.sh")
+ os.environ['LLDB_APPLE_DSYMFORUUID_EXECUTABLE'] = dsym_for_uuid
+ if self.TraceOn():
+ print("Setting env var LLDB_APPLE_DSYMFORUUID_EXECUTABLE=" + dsym_for_uuid)
self.addTearDownHook(lambda: os.environ.pop('LLDB_APPLE_DSYMFORUUID_EXECUTABLE', None))
self.runCmd("settings set target.load-script-from-symbol-file true")
self.addTearDownHook(lambda: self.runCmd("settings set target.load-script-from-symbol-file false"))
- dsym_python_dir = '%s.dSYM/Contents/Resources/Python' % (self.aout_exe)
+ dsym_python_dir = os.path.join('%s.dSYM' % aout_exe, 'Contents', 'Resources', 'Python')
os.makedirs(dsym_python_dir)
python_os_plugin_path = os.path.join(self.getSourceDir(),
'operating_system.py')
@@ -43,14 +191,14 @@ def initial_setup(self):
'def __lldb_init_module(debugger, internal_dict):',
' debugger.HandleCommand(\'settings set target.process.python-os-plugin-path %s\')' % python_os_plugin_path,
]
- with open(dsym_python_dir + "/a_out.py", "w") as writer:
+ with open(os.path.join(dsym_python_dir, "a_out.py"), "w") as writer:
for l in python_init:
writer.write(l + '\n')
dwarfdump_uuid_regex = re.compile(
'UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')
dwarfdump_cmd_output = subprocess.check_output(
- ('/usr/bin/dwarfdump --uuid "%s"' % self.aout_exe), shell=True).decode("utf-8")
+ ('/usr/bin/dwarfdump --uuid "%s"' % aout_exe), shell=True).decode("utf-8")
aout_uuid = None
for line in dwarfdump_cmd_output.splitlines():
match = dwarfdump_uuid_regex.search(line)
@@ -58,7 +206,7 @@ def initial_setup(self):
aout_uuid = match.group(1)
self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out")
- ### Create our dsym-for-uuid shell script which returns self.aout_exe
+ ### Create our dsym-for-uuid shell script which returns aout_exe
shell_cmds = [
'#! /bin/sh',
'# the last argument is the uuid',
@@ -78,8 +226,8 @@ def initial_setup(self):
' exit 1',
'fi',
' uuid=%s' % aout_uuid,
- ' bin=%s' % self.aout_exe,
- ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.aout_exe, os.path.basename(self.aout_exe)),
+ ' bin=%s' % aout_exe,
+ ' dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (aout_exe, os.path.basename(aout_exe)),
'echo "<dict><key>$uuid</key><dict>"',
'',
'echo "<key>DBGDSYMPath</key><string>$dsym</string>"',
@@ -88,30 +236,11 @@ def initial_setup(self):
'exit $ret'
]
- with open(self.dsym_for_uuid, "w") as writer:
+ with open(dsym_for_uuid, "w") as writer:
for l in shell_cmds:
writer.write(l + '\n')
- os.chmod(self.dsym_for_uuid, 0o755)
-
- self.slide = 0x70000000000
-
- ### Create our corefile
- # 0xffffffffffffffff means load address unknown
- retcode = call(self.create_corefile + " version-string " + self.verstr_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
- retcode = call(self.create_corefile + " version-string " + self.verstr_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
- retcode = call(self.create_corefile + " main-bin-spec " + self.binspec_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
- retcode = call(self.create_corefile + " main-bin-spec " + self.binspec_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
-
- @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
- @skipIf(archs=no_match(['x86_64']))
- @skipUnlessDarwin
- def test_lc_note_version_string(self):
- self.initial_setup()
-
- if self.TraceOn():
- self.runCmd("log enable lldb dyld host")
- self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
+ os.chmod(dsym_for_uuid, 0o755)
### Now run lldb on the corefile
### which will give us a UUID
@@ -119,135 +248,35 @@ def test_lc_note_version_string(self):
### which gives us a binary and dSYM
### which lldb should load!
- # First, try the "kern ver str" corefile
- self.target = self.dbg.CreateTarget('')
- err = lldb.SBError()
- if self.TraceOn():
- self.runCmd("script print('loading corefile %s')" % self.verstr_corefile)
- self.process = self.target.LoadCore(self.verstr_corefile)
- self.assertEqual(self.process.IsValid(), True)
- if self.TraceOn():
- self.runCmd("image list")
- self.runCmd("target mod dump sections")
- self.assertEqual(self.target.GetNumModules(), 1)
- fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
- self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
- self.process.Kill()
- self.process = None
- self.target.Clear()
- self.target = None
- self.dbg.MemoryPressureDetected()
-
- # Second, try the "kern ver str" corefile where it loads at an address
- self.target = self.dbg.CreateTarget('')
- err = lldb.SBError()
- if self.TraceOn():
- self.runCmd("script print('loading corefile %s')" % self.verstr_corefile_addr)
- self.process = self.target.LoadCore(self.verstr_corefile_addr)
- self.assertEqual(self.process.IsValid(), True)
- if self.TraceOn():
- self.runCmd("image list")
- self.runCmd("target mod dump sections")
- self.assertEqual(self.target.GetNumModules(), 1)
- fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
- self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
- main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
- main_addr = main_sym.GetStartAddress()
- self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
- self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)
- self.process.Kill()
- self.process = None
- self.target.Clear()
- self.target = None
- self.dbg.MemoryPressureDetected()
-
- @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
- @skipIf(archs=no_match(['x86_64']))
- @skipUnlessDarwin
- def test_lc_note_main_bin_spec(self):
- self.initial_setup()
-
- if self.TraceOn():
- self.runCmd("log enable lldb dyld host")
- self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
-
- # Third, try the "main bin spec" corefile
- self.target = self.dbg.CreateTarget('')
- if self.TraceOn():
- self.runCmd("script print('loading corefile %s')" % self.binspec_corefile)
- self.process = self.target.LoadCore(self.binspec_corefile)
- self.assertEqual(self.process.IsValid(), True)
- if self.TraceOn():
- self.runCmd("image list")
- self.runCmd("target mod dump sections")
- self.assertEqual(self.target.GetNumModules(), 1)
- fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
- self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
- self.process.Kill()
- self.process = None
- self.target.Clear()
- self.target = None
- self.dbg.MemoryPressureDetected()
-
- # Fourth, try the "main bin spec" corefile where it loads at an address
- self.target = self.dbg.CreateTarget('')
- if self.TraceOn():
- self.runCmd("script print('loading corefile %s')" % self.binspec_corefile_addr)
- self.process = self.target.LoadCore(self.binspec_corefile_addr)
- self.assertEqual(self.process.IsValid(), True)
- if self.TraceOn():
- self.runCmd("image list")
- self.runCmd("target mod dump sections")
- self.assertEqual(self.target.GetNumModules(), 1)
- fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
- self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
- main_sym = self.target.GetModuleAtIndex(0).FindSymbol("main", lldb.eSymbolTypeAny)
- main_addr = main_sym.GetStartAddress()
- self.assertGreater(main_addr.GetLoadAddress(self.target), self.slide)
- self.assertNotEqual(main_addr.GetLoadAddress(self.target), lldb.LLDB_INVALID_ADDRESS)
- self.process.Kill()
- self.process = None
- self.target.Clear()
- self.target = None
- self.dbg.MemoryPressureDetected()
-
- @skipIf(debug_info=no_match(["dsym"]), bugnumber="This test is looking explicitly for a dSYM")
- @skipIf(archs=no_match(['x86_64']))
- @skipUnlessDarwin
- def test_lc_note_main_bin_spec_os_plugin(self):
- self.initial_setup()
-
if self.TraceOn():
self.runCmd("log enable lldb dyld host")
self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld host"))
# Now load the binary and confirm that we load the OS plugin.
- self.target = self.dbg.CreateTarget('')
+ target = self.dbg.CreateTarget('')
if self.TraceOn():
- self.runCmd("script print('loading corefile %s with OS plugin')" % self.binspec_corefile_addr)
- self.process = self.target.LoadCore(self.binspec_corefile_addr)
- self.assertEqual(self.process.IsValid(), True)
+ self.runCmd("script print('loading corefile %s with OS plugin')" % binspec_corefile_addr)
+
+ process = target.LoadCore(binspec_corefile_addr)
+ self.assertEqual(process.IsValid(), True)
if self.TraceOn():
self.runCmd("image list")
self.runCmd("target mod dump sections")
self.runCmd("thread list")
- self.assertEqual(self.target.GetNumModules(), 1)
- fspec = self.target.GetModuleAtIndex(0).GetFileSpec()
- self.assertEqual(fspec.GetFilename(), self.aout_exe_basename)
+ self.assertEqual(target.GetNumModules(), 1)
+ fspec = target.GetModuleAtIndex(0).GetFileSpec()
+ self.assertEqual(fspec.GetFilename(), aout_exe_basename)
# Verify our OS plug-in threads showed up
- thread = self.process.GetThreadByID(0x111111111)
+ thread = process.GetThreadByID(0x111111111)
self.assertTrue(thread.IsValid(),
"Make sure there is a thread 0x111111111 after we load the python OS plug-in")
- thread = self.process.GetThreadByID(0x222222222)
+ thread = process.GetThreadByID(0x222222222)
self.assertTrue(thread.IsValid(),
"Make sure there is a thread 0x222222222 after we load the python OS plug-in")
- thread = self.process.GetThreadByID(0x333333333)
+ thread = process.GetThreadByID(0x333333333)
self.assertTrue(thread.IsValid(),
"Make sure there is a thread 0x333333333 after we load the python OS plug-in")
- self.process.Kill()
- self.process = None
- self.target.Clear()
- self.target = None
- self.dbg.MemoryPressureDetected()
+ self.runCmd("settings clear target.process.python-os-plugin-path")
+ self.dbg.DeleteTarget(target)
diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp b/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp
index 2845fd453150e..8bd6aaabecd63 100644
--- a/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp
+++ b/lldb/test/API/macosx/lc-note/firmware-corefile/create-empty-corefile.cpp
@@ -20,9 +20,10 @@ struct main_bin_spec_payload {
uint32_t version;
uint32_t type;
uint64_t address;
+ uint64_t slide;
uuid_t uuid;
uint32_t log2_pagesize;
- uint32_t unused;
+ uint32_t platform;
};
union uint32_buf {
@@ -49,33 +50,36 @@ void add_uint32(std::vector<uint8_t> &buf, uint32_t val) {
buf.push_back(conv.bytebuf[i]);
}
-std::vector<uint8_t> x86_lc_thread_load_command() {
+std::vector<uint8_t> lc_thread_load_command(cpu_type_t cputype) {
std::vector<uint8_t> data;
- add_uint32(data, LC_THREAD); // thread_command.cmd
- add_uint32(data, 184); // thread_command.cmdsize
- add_uint32(data, x86_THREAD_STATE64); // thread_command.flavor
- add_uint32(data, x86_THREAD_STATE64_COUNT); // thread_command.count
- add_uint64(data, 0x0000000000000000); // rax
- add_uint64(data, 0x0000000000000400); // rbx
- add_uint64(data, 0x0000000000000000); // rcx
- add_uint64(data, 0x0000000000000000); // rdx
- add_uint64(data, 0x0000000000000000); // rdi
- add_uint64(data, 0x0000000000000000); // rsi
- add_uint64(data, 0xffffff9246e2ba20); // rbp
- add_uint64(data, 0xffffff9246e2ba10); // rsp
- add_uint64(data, 0x0000000000000000); // r8
- add_uint64(data, 0x0000000000000000); // r9
- add_uint64(data, 0x0000000000000000); // r10
- add_uint64(data, 0x0000000000000000); // r11
- add_uint64(data, 0xffffff7f96ce5fe1); // r12
- add_uint64(data, 0x0000000000000000); // r13
- add_uint64(data, 0x0000000000000000); // r14
- add_uint64(data, 0xffffff9246e2bac0); // r15
- add_uint64(data, 0xffffff8015a8f6d0); // rip
- add_uint64(data, 0x0000000000011111); // rflags
- add_uint64(data, 0x0000000000022222); // cs
- add_uint64(data, 0x0000000000033333); // fs
- add_uint64(data, 0x0000000000044444); // gs
+ // Emit an LC_THREAD register context appropriate for the cputype
+ // of the binary we're embedded. The tests in this case do not
+ // use the register values, so 0's are fine, lldb needs to see at
+ // least one LC_THREAD in the corefile.
+#if defined(__x86_64__)
+ if (cputype == CPU_TYPE_X86_64) {
+ add_uint32(data, LC_THREAD); // thread_command.cmd
+ add_uint32(data,
+ 16 + (x86_THREAD_STATE64_COUNT * 4)); // thread_command.cmdsize
+ add_uint32(data, x86_THREAD_STATE64); // thread_command.flavor
+ add_uint32(data, x86_THREAD_STATE64_COUNT); // thread_command.count
+ for (int i = 0; i < x86_THREAD_STATE64_COUNT; i++) {
+ add_uint32(data, 0); // whatever, just some empty register values
+ }
+ }
+#endif
+#if defined(__arm64__) || defined(__aarch64__)
+ if (cputype == CPU_TYPE_ARM64) {
+ add_uint32(data, LC_THREAD); // thread_command.cmd
+ add_uint32(data,
+ 16 + (ARM_THREAD_STATE64_COUNT * 4)); // thread_command.cmdsize
+ add_uint32(data, ARM_THREAD_STATE64); // thread_command.flavor
+ add_uint32(data, ARM_THREAD_STATE64_COUNT); // thread_command.count
+ for (int i = 0; i < ARM_THREAD_STATE64_COUNT; i++) {
+ add_uint32(data, 0); // whatever, just some empty register values
+ }
+ }
+#endif
return data;
}
@@ -121,7 +125,8 @@ void add_lc_note_kern_ver_str_load_command(
void add_lc_note_main_bin_spec_load_command(
std::vector<std::vector<uint8_t>> &loadcmds, std::vector<uint8_t> &payload,
- int payload_file_offset, std::string uuidstr, uint64_t address) {
+ int payload_file_offset, std::string uuidstr, uint64_t address,
+ uint64_t slide) {
std::vector<uint8_t> loadcmd_data;
add_uint32(loadcmd_data, LC_NOTE); // note_command.cmd
@@ -145,15 +150,16 @@ void add_lc_note_main_bin_spec_load_command(
loadcmds.push_back(loadcmd_data);
// Now write the "main bin spec" payload.
- add_uint32(payload, 1); // version
+ add_uint32(payload, 2); // version
add_uint32(payload, 3); // type == 3 [ firmware, standalone, etc ]
add_uint64(payload, address); // load address
+ add_uint64(payload, slide); // slide
uuid_t uuid;
uuid_parse(uuidstr.c_str(), uuid);
for (int i = 0; i < sizeof(uuid_t); i++)
payload.push_back(uuid[i]);
add_uint32(payload, 0); // log2_pagesize unspecified
- add_uint32(payload, 0); // unused
+ add_uint32(payload, 0); // platform unspecified
}
void add_lc_segment(std::vector<std::vector<uint8_t>> &loadcmds,
@@ -179,7 +185,8 @@ void add_lc_segment(std::vector<std::vector<uint8_t>> &loadcmds,
loadcmds.push_back(loadcmd_data);
}
-std::string get_uuid_from_binary(const char *fn) {
+std::string get_uuid_from_binary(const char *fn, cpu_type_t &cputype,
+ cpu_subtype_t &cpusubtype) {
FILE *f = fopen(fn, "r");
if (f == nullptr) {
fprintf(stderr, "Unable to open binary '%s' to get uuid\n", fn);
@@ -213,9 +220,9 @@ std::string get_uuid_from_binary(const char *fn) {
fprintf(stderr, "error reading mach header from input file\n");
exit(1);
}
- if (mh.cputype != CPU_TYPE_X86_64) {
+ if (mh.cputype != CPU_TYPE_X86_64 && mh.cputype != CPU_TYPE_ARM64) {
fprintf(stderr,
- "This tool creates an x86_64 corefile but "
+ "This tool creates an x86_64/arm64 corefile but "
"the supplied binary '%s' is cputype 0x%x\n",
fn, (uint32_t)mh.cputype);
exit(1);
@@ -223,15 +230,17 @@ std::string get_uuid_from_binary(const char *fn) {
num_of_load_cmds = mh.ncmds;
size_of_load_cmds = mh.sizeofcmds;
file_offset += sizeof(struct mach_header);
+ cputype = mh.cputype;
+ cpusubtype = mh.cpusubtype;
} else {
struct mach_header_64 mh;
if (::fread(&mh, 1, sizeof(mh), f) != sizeof(mh)) {
fprintf(stderr, "error reading mach header from input file\n");
exit(1);
}
- if (mh.cputype != CPU_TYPE_X86_64) {
+ if (mh.cputype != CPU_TYPE_X86_64 && mh.cputype != CPU_TYPE_ARM64) {
fprintf(stderr,
- "This tool creates an x86_64 corefile but "
+ "This tool creates an x86_64/arm64 corefile but "
"the supplied binary '%s' is cputype 0x%x\n",
fn, (uint32_t)mh.cputype);
exit(1);
@@ -239,6 +248,8 @@ std::string get_uuid_from_binary(const char *fn) {
num_of_load_cmds = mh.ncmds;
size_of_load_cmds = mh.sizeofcmds;
file_offset += sizeof(struct mach_header_64);
+ cputype = mh.cputype;
+ cpusubtype = mh.cpusubtype;
}
off_t load_cmds_offset = file_offset;
@@ -269,12 +280,15 @@ std::string get_uuid_from_binary(const char *fn) {
}
int main(int argc, char **argv) {
- if (argc != 5) {
- fprintf(stderr,
- "usage: create-empty-corefile version-string|main-bin-spec "
- "<output-core-name> <binary-to-copy-uuid-from> <address>\n");
+ if (argc != 6) {
+ fprintf(
+ stderr,
+ "usage: create-empty-corefile version-string|main-bin-spec "
+ "<output-core-name> <binary-to-copy-uuid-from> <address> <slide>\n");
fprintf(stderr,
" <address> is base 16, 0xffffffffffffffff means unknown\n");
+ fprintf(stderr,
+ " <slide> is base 16, 0xffffffffffffffff means unknown\n");
fprintf(
stderr,
"Create a Mach-O corefile with an either LC_NOTE 'kern ver str' or \n");
@@ -289,7 +303,9 @@ int main(int argc, char **argv) {
exit(1);
}
- std::string uuid = get_uuid_from_binary(argv[3]);
+ cpu_type_t cputype;
+ cpu_subtype_t cpusubtype;
+ std::string uuid = get_uuid_from_binary(argv[3], cputype, cpusubtype);
// An array of load commands (in the form of byte arrays)
std::vector<std::vector<uint8_t>> load_commands;
@@ -304,15 +320,22 @@ int main(int argc, char **argv) {
exit(1);
}
+ errno = 0;
+ uint64_t slide = strtoull(argv[5], NULL, 16);
+ if (errno != 0) {
+ fprintf(stderr, "Unable to parse slide %s as base 16", argv[4]);
+ exit(1);
+ }
+
// First add all the load commands / payload so we can figure out how large
// the load commands will actually be.
- load_commands.push_back(x86_lc_thread_load_command());
+ load_commands.push_back(lc_thread_load_command(cputype));
if (strcmp(argv[1], "version-string") == 0)
add_lc_note_kern_ver_str_load_command(load_commands, payload, 0, uuid,
address);
else
add_lc_note_main_bin_spec_load_command(load_commands, payload, 0, uuid,
- address);
+ address, slide);
add_lc_segment(load_commands, payload, 0);
int size_of_load_commands = 0;
@@ -327,22 +350,22 @@ int main(int argc, char **argv) {
load_commands.clear();
payload.clear();
- load_commands.push_back(x86_lc_thread_load_command());
+ load_commands.push_back(lc_thread_load_command(cputype));
if (strcmp(argv[1], "version-string") == 0)
add_lc_note_kern_ver_str_load_command(
load_commands, payload, header_and_load_cmd_room, uuid, address);
else
add_lc_note_main_bin_spec_load_command(
- load_commands, payload, header_and_load_cmd_room, uuid, address);
+ load_commands, payload, header_and_load_cmd_room, uuid, address, slide);
add_lc_segment(load_commands, payload, header_and_load_cmd_room);
struct mach_header_64 mh;
mh.magic = MH_MAGIC_64;
- mh.cputype = CPU_TYPE_X86_64;
+ mh.cputype = cputype;
- mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
+ mh.cpusubtype = cpusubtype;
mh.filetype = MH_CORE;
mh.ncmds = load_commands.size();
mh.sizeofcmds = size_of_load_commands;
More information about the lldb-commits
mailing list