Reorg firmware corefile tests; add test for OS plugin loading

A little cleanup to how these firmware corefile tests are done; add
a test that loads a dSYM that loads an OS plugin, and confirm that
the OS plugin's threads are created.

GitOrigin-RevId: d9773c1b4eb14c5f38d23323270ef67b4c528844
diff --git a/test/API/macosx/lc-note/firmware-corefile/Makefile b/test/API/macosx/lc-note/firmware-corefile/Makefile
index faa5ef2..0502011 100644
--- a/test/API/macosx/lc-note/firmware-corefile/Makefile
+++ b/test/API/macosx/lc-note/firmware-corefile/Makefile
@@ -1,14 +1,11 @@
 MAKE_DSYM := NO
 C_SOURCES := main.c
-CFLAGS_EXTRAS := -Wl,-random_uuid
+#CFLAGS_EXTRAS := 
 
-all: a.out b.out create-empty-corefile
+all: a.out create-empty-corefile
 
 create-empty-corefile:
-	$(MAKE) -f $(MAKEFILE_RULES) EXE=create-empty-corefile \
+	"$(MAKE)" -f "$(MAKEFILE_RULES)" EXE=create-empty-corefile \
 		C_SOURCES=create-empty-corefile.c
 
-b.out:
-	$(MAKE)  VPATH=$(SRCDIR)/$* -I $(SRCDIR) -f $(SRCDIR)/bout.mk
-
 include Makefile.rules
diff --git a/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py b/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
index 068848b..a28b01b 100644
--- a/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
+++ b/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py
@@ -16,25 +16,37 @@
 
     mydir = TestBase.compute_mydir(__file__)
 
-    @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(self):
+    def initial_setup(self):
         self.build()
         self.aout_exe = self.getBuildArtifact("a.out")
-        self.bout_exe = self.getBuildArtifact("b.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.aout_corefile = self.getBuildArtifact("aout.core")
-        self.aout_corefile_addr = self.getBuildArtifact("aout.core_addr")
-        self.bout_corefile = self.getBuildArtifact("bout.core")
-        self.bout_corefile_addr = self.getBuildArtifact("bout.core_addr")
+        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")
 
         ## 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
         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)
+        os.makedirs(dsym_python_dir)
+        python_os_plugin_path = os.path.join(self.getSourceDir(),
+                                             'operating_system.py')
+        python_init = [
+                '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:
+            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(
@@ -46,17 +58,7 @@
                 aout_uuid = match.group(1)
         self.assertNotEqual(aout_uuid, None, "Could not get uuid of built a.out")
 
-        dwarfdump_cmd_output = subprocess.check_output(
-                ('/usr/bin/dwarfdump --uuid "%s"' % self.bout_exe), shell=True).decode("utf-8")
-        bout_uuid = None
-        for line in dwarfdump_cmd_output.splitlines():
-            match = dwarfdump_uuid_regex.search(line)
-            if match:
-                bout_uuid = match.group(1)
-        self.assertNotEqual(bout_uuid, None, "Could not get uuid of built b.out")
-
         ###  Create our dsym-for-uuid shell script which returns self.aout_exe
-        ###  or self.bout_exe, depending on the UUID on the command line.
         shell_cmds = [
                 '#! /bin/sh',
                 '# the last argument is the uuid',
@@ -69,25 +71,17 @@
                 'echo "<!DOCTYPE plist PUBLIC \\"-//Apple//DTD PLIST 1.0//EN\\" \\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\\">"',
                 'echo "<plist version=\\"1.0\\">"',
                 '',
-                'if [ "$1" != "%s" -a "$1" != "%s" ]' % (aout_uuid, bout_uuid),
+                'if [ "$1" != "%s" ]' % (aout_uuid),
                 'then',
                 '  echo "<key>DBGError</key><string>not found</string>"',
                 '  echo "</plist>"', 
                 '  exit 1',
                 'fi',
-                'if [ "$1" = "%s" ]' % aout_uuid,
-                'then',
                 '  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)),
-                'else',
-                '  uuid=%s' % bout_uuid,
-                '  bin=%s' % self.bout_exe,
-                '  dsym=%s.dSYM/Contents/Resources/DWARF/%s' % (self.bout_exe, os.path.basename(self.bout_exe)),
-                'fi',
                 'echo "<dict><key>$uuid</key><dict>"',
                 '',
-                'echo "<key>DBGArchitecture</key><string>i386</string>"',
                 'echo "<key>DBGDSYMPath</key><string>$dsym</string>"',
                 'echo "<key>DBGSymbolRichExecutable</key><string>$bin</string>"',
                 'echo "</dict></dict></plist>"',
@@ -103,10 +97,21 @@
         self.slide = 0x70000000000
 
         ### Create our corefile
-        retcode = call(self.create_corefile + " version-string " + self.aout_corefile + " " + self.aout_exe + " 0xffffffffffffffff", shell=True)
-        retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile + " " + self.bout_exe + " 0xffffffffffffffff", shell=True)
-        retcode = call(self.create_corefile + " version-string " + self.aout_corefile_addr + " " + self.aout_exe + (" 0x%x" % self.slide), shell=True)
-        retcode = call(self.create_corefile + " main-bin-spec " + self.bout_corefile_addr + " " + self.bout_exe + (" 0x%x" % self.slide), shell=True)
+        # 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"))
 
         ### Now run lldb on the corefile
         ### which will give us a UUID
@@ -118,60 +123,131 @@
         self.target = self.dbg.CreateTarget('')
         err = lldb.SBError()
         if self.TraceOn():
-            self.runCmd("log enable lldb dyld")
-            self.addTearDownHook(lambda: self.runCmd("log disable lldb dyld"))
-
-        self.process = self.target.LoadCore(self.aout_corefile)
+            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()
-        filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
-        self.assertEqual(filepath, self.aout_exe)
+        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()
-        self.process = self.target.LoadCore(self.aout_corefile_addr)
+        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()
-        filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
-        self.assertEqual(filepath, self.aout_exe)
+        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('')
-        self.process = self.target.LoadCore(self.bout_corefile)
+        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()
-        filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
-        self.assertEqual(filepath, self.bout_exe)
+        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('')
-        self.process = self.target.LoadCore(self.bout_corefile_addr)
+        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()
-        filepath = fspec.GetDirectory() + "/" + fspec.GetFilename()
-        self.assertEqual(filepath, self.bout_exe)
+        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('')
+
+        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)
+        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)
+
+        # Verify our OS plug-in threads showed up
+        thread = self.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)
+        self.assertTrue(thread.IsValid(), 
+                "Make sure there is a thread 0x222222222 after we load the python OS plug-in")
+        thread = self.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()
diff --git a/test/API/macosx/lc-note/firmware-corefile/bout.mk b/test/API/macosx/lc-note/firmware-corefile/bout.mk
deleted file mode 100644
index 049b7b4..0000000
--- a/test/API/macosx/lc-note/firmware-corefile/bout.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-MAKE_DSYM := NO
-
-C_SOURCES := main.c
-CFLAGS_EXTRAS := -Wl,-random_uuid
-
-EXE := b.out
-
-all: b.out 
-
-include Makefile.rules
diff --git a/test/API/macosx/lc-note/firmware-corefile/main.c b/test/API/macosx/lc-note/firmware-corefile/main.c
index 70a72e0..911ebc8 100644
--- a/test/API/macosx/lc-note/firmware-corefile/main.c
+++ b/test/API/macosx/lc-note/firmware-corefile/main.c
@@ -1,2 +1,2 @@
 #include <stdio.h>
-int main () { puts ("this is the lc-note test program."); }
+int main () { puts ("this is the standalone binary test program"); }
diff --git a/test/API/macosx/lc-note/firmware-corefile/operating_system.py b/test/API/macosx/lc-note/firmware-corefile/operating_system.py
new file mode 100644
index 0000000..95a5bdc
--- /dev/null
+++ b/test/API/macosx/lc-note/firmware-corefile/operating_system.py
@@ -0,0 +1,44 @@
+import lldb
+
+
+class OperatingSystemPlugIn(object):
+    """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
+
+    def __init__(self, process):
+        '''Initialization needs a valid.SBProcess object.
+
+        This plug-in will get created after a live process is valid and has stopped for the first time.
+        '''
+        self.process = None
+        self.registers = None
+        self.threads = None
+        if isinstance(process, lldb.SBProcess) and process.IsValid():
+            self.process = process
+            self.threads = None  # Will be an dictionary containing info for each thread
+
+    def get_target(self):
+        return self.process.target
+
+    def get_thread_info(self):
+        if not self.threads:
+            self.threads = [{
+                'tid': 0x111111111,
+                'name': 'one',
+                'queue': 'queue1',
+                'state': 'stopped',
+                'stop_reason': 'none'
+            }, {
+                'tid': 0x222222222,
+                'name': 'two',
+                'queue': 'queue2',
+                'state': 'stopped',
+                'stop_reason': 'none'
+            }, {
+                'tid': 0x333333333,
+                'name': 'three',
+                'queue': 'queue3',
+                'state': 'stopped',
+                'stop_reason': 'sigstop',
+                'core': 0
+            }]
+        return self.threads