brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.7 KiB · 2a3d291 Raw
447 lines · python
1"""2Test basics of Minidump debugging.3"""4 5import lldb6import os7from lldbsuite.test.decorators import *8from lldbsuite.test.lldbtest import *9from lldbsuite.test import lldbutil10 11 12class MiniDumpUUIDTestCase(TestBase):13    NO_DEBUG_INFO_TESTCASE = True14 15    def verify_module(self, module, verify_path, verify_uuid):16        # Compare the filename and the directory separately. We are avoiding17        # SBFileSpec.fullpath because it causes a slash/backslash confusion18        # on Windows.  Similarly, we compare the directories using normcase19        # because they may contain a Linux-style relative path from the20        # minidump appended to a Windows-style root path from the host.21        self.assertEqual(os.path.basename(verify_path), module.GetFileSpec().basename)22        self.assertEqual(23            os.path.normcase(os.path.dirname(verify_path)),24            os.path.normcase(module.GetFileSpec().dirname or ""),25        )26        self.assertEqual(verify_uuid, module.GetUUIDString())27 28    def get_minidump_modules(self, yaml_file, exe=None):29        minidump_path = self.getBuildArtifact(os.path.basename(yaml_file) + ".dmp")30        self.yaml2obj(yaml_file, minidump_path)31        self.target = self.dbg.CreateTarget(exe)32        self.process = self.target.LoadCore(minidump_path)33        return self.target.modules34 35    def test_zero_uuid_modules(self):36        """37        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,38        but contains a PDB70 value whose age is zero and whose UUID values are39        all zero. Prior to a fix all such modules would be duplicated to the40        first one since the UUIDs claimed to be valid and all zeroes. Now we41        ensure that the UUID is not valid for each module and that we have42        each of the modules in the target after loading the core43        """44        modules = self.get_minidump_modules("linux-arm-zero-uuids.yaml")45        self.assertEqual(2, len(modules))46        self.verify_module(modules[0], "/file/does/not/exist/a", None)47        self.verify_module(modules[1], "/file/does/not/exist/b", None)48 49    def test_uuid_modules_no_age(self):50        """51        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,52        and contains a PDB70 value whose age is zero and whose UUID values are53        valid. Ensure we decode the UUID and don't include the age field in the UUID.54        """55        modules = self.get_minidump_modules("linux-arm-uuids-no-age.yaml")56        modules = self.target.modules57        self.assertEqual(2, len(modules))58        self.verify_module(modules[0], "/tmp/a", "01020304-0506-0708-090A-0B0C0D0E0F10")59        self.verify_module(modules[1], "/tmp/b", "0A141E28-323C-4650-5A64-6E78828C96A0")60 61    def test_uuid_modules_no_age_apple(self):62        """63        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,64        and contains a PDB70 value whose age is zero and whose UUID values are65        valid. Ensure we decode the UUID and don't include the age field in the UUID.66        Also ensure that the first uint32_t is byte swapped, along with the next67        two uint16_t values. Breakpad incorrectly byte swaps these values when it68        saves Darwin minidump files.69        """70        modules = self.get_minidump_modules("macos-arm-uuids-no-age.yaml")71        modules = self.target.modules72        self.assertEqual(2, len(modules))73        self.verify_module(modules[0], "/tmp/a", "04030201-0605-0807-090A-0B0C0D0E0F10")74        self.verify_module(modules[1], "/tmp/b", "281E140A-3C32-5046-5A64-6E78828C96A0")75 76    def test_uuid_modules_with_age(self):77        """78        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,79        and contains a PDB70 value whose age is valid and whose UUID values are80        valid. Ensure we decode the UUID and include the age field in the UUID.81        """82        modules = self.get_minidump_modules("linux-arm-uuids-with-age.yaml")83        self.assertEqual(2, len(modules))84        self.verify_module(85            modules[0], "/tmp/a", "01020304-0506-0708-090A-0B0C0D0E0F10-10101010"86        )87        self.verify_module(88            modules[1], "/tmp/b", "0A141E28-323C-4650-5A64-6E78828C96A0-20202020"89        )90 91    def test_uuid_modules_elf_build_id_16(self):92        """93        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,94        and contains an ELF build ID whose value is valid and is 16 bytes long.95        """96        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-16.yaml")97        self.assertEqual(2, len(modules))98        self.verify_module(modules[0], "/tmp/a", "01020304-0506-0708-090A-0B0C0D0E0F10")99        self.verify_module(modules[1], "/tmp/b", "0A141E28-323C-4650-5A64-6E78828C96A0")100 101    def test_uuid_modules_elf_build_id_20(self):102        """103        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,104        and contains an ELF build ID whose value is valid and is 20 bytes long.105        """106        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-20.yaml")107        self.assertEqual(2, len(modules))108        self.verify_module(109            modules[0], "/tmp/a", "01020304-0506-0708-090A-0B0C0D0E0F10-11121314"110        )111        self.verify_module(112            modules[1], "/tmp/b", "0A141E28-323C-4650-5A64-6E78828C96A0-AAB4BEC8"113        )114 115    def test_uuid_modules_elf_build_id_zero(self):116        """117        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is valid,118        and contains an ELF build ID whose value is all zero.119        """120        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-zero.yaml")121        self.assertEqual(2, len(modules))122        self.verify_module(modules[0], "/not/exist/a", None)123        self.verify_module(modules[1], "/not/exist/b", None)124 125    def test_uuid_modules_elf_build_id_same(self):126        """127        Test multiple modules having a MINIDUMP_MODULE.CvRecord that is128        valid, and contains an ELF build ID whose value is the same. There129        is an assert in the PlaceholderObjectFile that was firing when we130        encountered this which was crashing the process that was checking131        if PlaceholderObjectFile.m_base was the same as the address this132        fake module was being loaded at. We need to ensure we don't crash133        in such cases and that we add both modules even though they have134        the same UUID.135        """136        modules = self.get_minidump_modules("linux-arm-same-uuids.yaml")137        self.assertEqual(2, len(modules))138        self.verify_module(139            modules[0],140            "/file/does/not/exist/a",141            "11223344-1122-3344-1122-334411223344-11223344",142        )143        self.verify_module(144            modules[1],145            "/file/does/not/exist/b",146            "11223344-1122-3344-1122-334411223344-11223344",147        )148 149    def test_partial_uuid_match(self):150        """151        Breakpad has been known to create minidump files using CvRecord in each152        module whose signature is set to PDB70 where the UUID only contains the153        first 16 bytes of a 20 byte ELF build ID. Code was added to154        ProcessMinidump.cpp to deal with this and allows partial UUID matching.155 156        This test verifies that if we have a minidump with a 16 byte UUID, that157        we are able to associate a symbol file with a 20 byte UUID only if the158        first 16 bytes match. In this case we will see the path from the file159        we found in the test directory and the 20 byte UUID from the actual160        file, not the 16 byte shortened UUID from the minidump.161        """162        so_path = self.getBuildArtifact("libuuidmatch.so")163        self.yaml2obj("libuuidmatch.yaml", so_path)164        cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))165        self.dbg.HandleCommand(cmd)166        modules = self.get_minidump_modules("linux-arm-partial-uuids-match.yaml")167        self.assertEqual(1, len(modules))168        self.verify_module(169            modules[0], so_path, "7295E17C-6668-9E05-CBB5-DEE5003865D5-5267C116"170        )171 172    def test_partial_uuid_mismatch(self):173        """174        Breakpad has been known to create minidump files using CvRecord in each175        module whose signature is set to PDB70 where the UUID only contains the176        first 16 bytes of a 20 byte ELF build ID. Code was added to177        ProcessMinidump.cpp to deal with this and allows partial UUID matching.178 179        This test verifies that if we have a minidump with a 16 byte UUID, that180        we are not able to associate a symbol file with a 20 byte UUID only if181        any of the first 16 bytes do not match. In this case we will see the UUID182        from the minidump file and the path from the minidump file.183        """184        so_path = self.getBuildArtifact("libuuidmismatch.so")185        self.yaml2obj("libuuidmismatch.yaml", so_path)186        cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))187        self.dbg.HandleCommand(cmd)188        modules = self.get_minidump_modules("linux-arm-partial-uuids-mismatch.yaml")189        self.assertEqual(1, len(modules))190        self.verify_module(191            modules[0],192            "/invalid/path/on/current/system/libuuidmismatch.so",193            "7295E17C-6668-9E05-CBB5-DEE5003865D5",194        )195 196    def test_breakpad_hash_match(self):197        """198        Breakpad creates minidump files using CvRecord in each module whose199        signature is set to PDB70 where the UUID is a hash generated by200        breakpad of the .text section. This is only done when the201        executable has no ELF build ID.202 203        This test verifies that if we have a minidump with a 16 byte UUID,204        that we are able to associate a symbol file with no ELF build ID205        and match it up by hashing the .text section.206        """207        so_path = self.getBuildArtifact("libbreakpad.so")208        self.yaml2obj("libbreakpad.yaml", so_path)209        cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))210        self.dbg.HandleCommand(cmd)211        modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml")212        self.assertEqual(1, len(modules))213        # LLDB makes up it own UUID as well when there is no build ID so we214        # will check that this matches.215        self.verify_module(modules[0], so_path, "D9C480E8")216 217    def test_breakpad_hash_match_sysroot(self):218        """219        Check that we can match the breakpad .text section hash when the220        module is located under a user-provided sysroot.221        """222        sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot")223        # Create the directory under the sysroot where the minidump reports224        # the module.225        so_dir = os.path.join(226            sysroot_path, "invalid", "path", "on", "current", "system"227        )228        so_path = os.path.join(so_dir, "libbreakpad.so")229        lldbutil.mkdir_p(so_dir)230        self.yaml2obj("libbreakpad.yaml", so_path)231        self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path)232        modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml")233        self.assertEqual(1, len(modules))234        # LLDB makes up its own UUID as well when there is no build ID so we235        # will check that this matches.236        self.verify_module(modules[0], so_path, "D9C480E8")237 238    def test_breakpad_hash_match_sysroot_decoy(self):239        """240        Check that we can match the breakpad .text section hash when there is241        a module with the right name but wrong contents under a user-provided242        sysroot, and the right module is at the given search path..243        """244        sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot")245        # Create the directory under the sysroot where the minidump reports246        # the module.247        decoy_dir = os.path.join(248            sysroot_path, "invalid", "path", "on", "current", "system"249        )250        decoy_path = os.path.join(decoy_dir, "libbreakpad.so")251        lldbutil.mkdir_p(decoy_dir)252        self.yaml2obj("libbreakpad-decoy.yaml", decoy_path)253        self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path)254        so_dir = os.path.join(self.getBuildDir(), "searchpath_dir")255        so_path = os.path.join(so_dir, "libbreakpad.so")256        lldbutil.mkdir_p(so_dir)257        self.yaml2obj("libbreakpad.yaml", so_path)258        self.runCmd('settings set target.exec-search-paths "%s"' % so_dir)259        modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml")260        self.assertEqual(1, len(modules))261        # LLDB makes up its own UUID as well when there is no build ID so we262        # will check that this matches.263        self.verify_module(modules[0], so_path, "D9C480E8")264 265    def test_breakpad_overflow_hash_match(self):266        """267        This is a similar to test_breakpad_hash_match, but it verifies that268        if the .text section does not end on a 16 byte boundary, then it269        will overflow into the next section's data by up to 15 bytes. This270        verifies that we are able to match what breakpad does as it will do271        this.272        """273        so_path = self.getBuildArtifact("libbreakpad.so")274        self.yaml2obj("libbreakpad-overflow.yaml", so_path)275        cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))276        self.dbg.HandleCommand(cmd)277        modules = self.get_minidump_modules("linux-arm-breakpad-uuid-match.yaml")278        self.assertEqual(1, len(modules))279        # LLDB makes up it own UUID as well when there is no build ID so we280        # will check that this matches.281        self.verify_module(modules[0], so_path, "48EB9FD7")282 283    def test_breakpad_hash_match_exe_outside_sysroot(self):284        """285        Check that we can match the breakpad .text section hash when the286        module is specified as the exe during launch, and a syroot is287        provided, which does not contain the exe.288        """289        sysroot_path = os.path.join(self.getBuildDir(), "mock_sysroot")290        lldbutil.mkdir_p(sysroot_path)291        so_dir = os.path.join(self.getBuildDir(), "binary")292        so_path = os.path.join(so_dir, "libbreakpad.so")293        lldbutil.mkdir_p(so_dir)294        self.yaml2obj("libbreakpad.yaml", so_path)295        self.runCmd("platform select remote-linux --sysroot '%s'" % sysroot_path)296        modules = self.get_minidump_modules(297            "linux-arm-breakpad-uuid-match.yaml", so_path298        )299        self.assertEqual(1, len(modules))300        # LLDB makes up its own UUID as well when there is no build ID so we301        # will check that this matches.302        self.verify_module(modules[0], so_path, "D9C480E8")303 304    def test_facebook_hash_match(self):305        """306        Breakpad creates minidump files using CvRecord in each module whose307        signature is set to PDB70 where the UUID is a hash generated by308        breakpad of the .text section and Facebook modified this hash to309        avoid collisions. This is only done when the executable has no ELF310        build ID.311 312        This test verifies that if we have a minidump with a 16 byte UUID,313        that we are able to associate a symbol file with no ELF build ID314        and match it up by hashing the .text section like Facebook does.315        """316        so_path = self.getBuildArtifact("libbreakpad.so")317        self.yaml2obj("libbreakpad.yaml", so_path)318        cmd = 'settings set target.exec-search-paths "%s"' % (os.path.dirname(so_path))319        self.dbg.HandleCommand(cmd)320        modules = self.get_minidump_modules("linux-arm-facebook-uuid-match.yaml")321        self.assertEqual(1, len(modules))322        # LLDB makes up it own UUID as well when there is no build ID so we323        # will check that this matches.324        self.verify_module(modules[0], so_path, "D9C480E8")325 326    def test_relative_module_name(self):327        old_cwd = os.getcwd()328        self.addTearDownHook(lambda: os.chdir(old_cwd))329        os.chdir(self.getBuildDir())330        name = "file-with-a-name-unlikely-to-exist-in-the-current-directory.so"331        open(name, "a").close()332        modules = self.get_minidump_modules(333            self.getSourcePath("relative_module_name.yaml")334        )335        self.assertEqual(1, len(modules))336        self.verify_module(modules[0], name, None)337 338    def test_add_module_build_id_16(self):339        """340        Test that adding module with 16 byte UUID returns the existing341        module or fails.342        """343        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-16.yaml")344        self.assertEqual(2, len(modules))345 346        # Add the existing modules.347        self.assertEqual(348            modules[0],349            self.target.AddModule(350                "/some/local/a", "", "01020304-0506-0708-090A-0B0C0D0E0F10"351            ),352        )353        self.assertEqual(354            modules[1],355            self.target.AddModule(356                "/some/local/b", "", "0A141E28-323C-4650-5A64-6E78828C96A0"357            ),358        )359 360        # Adding modules with non-existing UUID should fail.361        self.assertFalse(362            self.target.AddModule(363                "a", "", "12345678-1234-1234-1234-123456789ABC"364            ).IsValid()365        )366        self.assertFalse(367            self.target.AddModule(368                "a", "", "01020304-0506-0708-090A-0B0C0D0E0F10-12345678"369            ).IsValid()370        )371 372    def test_add_module_build_id_20(self):373        """374        Test that adding module with 20 byte UUID returns the existing375        module or fails.376        """377        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-20.yaml")378 379        # Add the existing modules.380        self.assertEqual(381            modules[0],382            self.target.AddModule(383                "/some/local/a", "", "01020304-0506-0708-090A-0B0C0D0E0F10-11121314"384            ),385        )386        self.assertEqual(387            modules[1],388            self.target.AddModule(389                "/some/local/b", "", "0A141E28-323C-4650-5A64-6E78828C96A0-AAB4BEC8"390            ),391        )392 393        # Adding modules with non-existing UUID should fail.394        self.assertFalse(395            self.target.AddModule(396                "a", "", "01020304-0506-0708-090A-0B0C0D0E0F10"397            ).IsValid()398        )399        self.assertFalse(400            self.target.AddModule(401                "a", "", "01020304-0506-0708-090A-0B0C0D0E0F10-12345678"402            ).IsValid()403        )404 405    def test_add_module_build_id_4(self):406        """407        Test that adding module with 4 byte UUID returns the existing408        module or fails.409        """410        modules = self.get_minidump_modules("linux-arm-uuids-elf-build-id-4.yaml")411 412        # Add the existing modules.413        self.assertEqual(414            modules[0], self.target.AddModule("/some/local/a.so", "", "01020304")415        )416        self.assertEqual(417            modules[1], self.target.AddModule("/some/local/b.so", "", "0A141E28")418        )419 420        # Adding modules with non-existing UUID should fail.421        self.assertFalse(422            self.target.AddModule(423                "a", "", "01020304-0506-0708-090A-0B0C0D0E0F10"424            ).IsValid()425        )426        self.assertFalse(self.target.AddModule("a", "", "01020305").IsValid())427 428    def test_remove_placeholder_add_real_module(self):429        """430        Test that removing a placeholder module and adding back the real431        module succeeds.432        """433        so_path = self.getBuildArtifact("libuuidmatch.so")434        self.yaml2obj("libuuidmatch.yaml", so_path)435        modules = self.get_minidump_modules("linux-arm-uuids-match.yaml")436 437        uuid = "7295E17C-6668-9E05-CBB5-DEE5003865D5-5267C116"438        self.assertEqual(1, len(modules))439        self.verify_module(modules[0], "/target/path/libuuidmatch.so", uuid)440 441        self.target.RemoveModule(modules[0])442        new_module = self.target.AddModule(so_path, "", uuid)443 444        self.verify_module(new_module, so_path, uuid)445        self.assertEqual(new_module, self.target.modules[0])446        self.assertEqual(1, len(self.target.modules))447