diff --git a/buildscripts/resmokelib/hang_analyzer/extractor.py b/buildscripts/resmokelib/hang_analyzer/extractor.py index 19076e4e5a4..539a610c997 100644 --- a/buildscripts/resmokelib/hang_analyzer/extractor.py +++ b/buildscripts/resmokelib/hang_analyzer/extractor.py @@ -203,6 +203,36 @@ def download_multiversion_artifact( return False +def get_dwarf_version(dwarf_dump): + """ + Find the dwarf version of a compile unit that was produced by a MongoDB compiler or + has mongodb sources in its name. + + See a segment of a dwarf dump in buildscripts/tests/resmokelib/hang_analyzer/test_extractor.py + """ + + # Checks if a compile unit contains "mongo" or "src/third_party". + # The DW_AT_producer tag will contain the compiler used, which may be stamped with 'MongoDB' for our + # toolchain compilers. + # The DW_AT_name can contain the source file, for which we hope to find 'src/mongo' or 'src/third_party' + mongo_pattern = r"mongo|src/third_party" + version_pattern = r"version = 0x([0-9]{4})," + + for unit in dwarf_dump.split("Compile Unit"): + if re.search(mongo_pattern, unit, re.IGNORECASE): + matches = re.search(version_pattern, unit) + if matches: + return int(matches.group(1)) + + # If we didn't find any compile unit that looks like the patterns, fallback to ANY dwarf version + # listed in the output. + matches = re.search(version_pattern, dwarf_dump) + if matches: + return int(matches.group(1)) + + return None + + @TRACER.start_as_current_span("core_analyzer.post_install_gdb_optimization") def post_install_gdb_optimization(download_dir: str, root_looger: Logger): @TRACER.start_as_current_span("core_analyzer.post_install_gdb_optimization.add_index") @@ -228,9 +258,10 @@ def post_install_gdb_optimization(download_dir: str, root_looger: Logger): current_span.set_attribute("add_index_status", "skipped") return - # find dwarf version from output, it should always be present - regex = re.search("version = 0x([0-9]{4}),", process.stdout) - if not regex: + version = get_dwarf_version(process.stdout) + if version: + current_span.set_attribute("dwarf_version", version) + else: current_span.set_status(StatusCode.ERROR, "Could not find dwarf version in file.") current_span.set_attributes( { @@ -243,9 +274,7 @@ def post_install_gdb_optimization(download_dir: str, root_looger: Logger): return raise RuntimeError(f"Could not find dwarf version in file {file_path}") - version = int(regex.group(1)) target_dir = os.path.dirname(file_path) - current_span.set_attribute("dwarf_version", version) try: # logic copied from https://sourceware.org/gdb/onlinedocs/gdb/Index-Files.html diff --git a/buildscripts/tests/resmokelib/hang_analyzer/BUILD.bazel b/buildscripts/tests/resmokelib/hang_analyzer/BUILD.bazel index 3f66c063f08..fbc0bb9ab8a 100644 --- a/buildscripts/tests/resmokelib/hang_analyzer/BUILD.bazel +++ b/buildscripts/tests/resmokelib/hang_analyzer/BUILD.bazel @@ -41,3 +41,14 @@ py_test( ), ], ) + +py_test( + name = "test_extractor", + srcs = [ + "test_extractor.py", + ], + deps = [ + "//buildscripts/resmokelib", + "//buildscripts/resmokelib/hang_analyzer", + ], +) diff --git a/buildscripts/tests/resmokelib/hang_analyzer/test_extractor.py b/buildscripts/tests/resmokelib/hang_analyzer/test_extractor.py new file mode 100644 index 00000000000..816468120d9 --- /dev/null +++ b/buildscripts/tests/resmokelib/hang_analyzer/test_extractor.py @@ -0,0 +1,71 @@ +import unittest + +from buildscripts.resmokelib.hang_analyzer.extractor import get_dwarf_version + + +class TestExtractor(unittest.TestCase): + def test_find_dwarf_version(self): + """ + Test that DWARF version 5 is identified based on "format = DWARF32, version = 0x0005", and + that the compile unit for the system library with DWARF version 2 is ignored. + """ + + # This is an excerpt from `llvm-dwarfdump -r 0 dist-test/bin/mongod.debug` + dwarf_dump = """ +dist-test/bin/mongod.debug: file format elf64-x86-64 + +.debug_info contents: +0x00000000: Compile Unit: length = 0x00000041, format = DWARF32, version = 0x0002, abbr_offset = 0x0000, addr_size = 0x08 (next unit at 0x00000045) + +0x0000000b: DW_TAG_compile_unit + DW_AT_stmt_list (0x00000000) + DW_AT_low_pc (0x00000000042e7200) + DW_AT_high_pc (0x00000000042e722b) + DW_AT_name ("../sysdeps/x86_64/start.S") + DW_AT_comp_dir ("/home/abuild/rpmbuild/BUILD/glibc-2.31/csu") + DW_AT_producer ("GNU AS 2.43.1") + DW_AT_language (DW_LANG_Mips_Assembler) +0x00000045: Compile Unit: length = 0x0000003b, format = DWARF32, version = 0x0004, abbr_offset = 0x0021, addr_size = 0x08 (next unit at 0x00000084) + +0x00000050: DW_TAG_compile_unit + DW_AT_producer ("GNU C11 7.5.0 -mtune=generic -march=x86-64 -g -g -O2 -std=gnu11 -fgnu89-inline -fmessage-length=0 -funwind-tables -fasynchronous-unwind-tables -fstack-clash-protection -fmerge-all-constants -frounding-math -fstack-protector-strong -fpatchable-function-entry=16,14 -fmath-errno -fno-stack-protector -ftls-model=initial-exec -fPIE") + DW_AT_language (DW_LANG_C99) + DW_AT_name ("init.c") + DW_AT_comp_dir ("/home/abuild/rpmbuild/BUILD/glibc-2.31/csu") + DW_AT_stmt_list (0x00000059) +0x00000084: Compile Unit: length = 0x0000001e, format = DWARF32, version = 0x0002, abbr_offset = 0x0054, addr_size = 0x08 (next unit at 0x000000a6) + +0x0000008f: DW_TAG_compile_unit + DW_AT_stmt_list (0x00000080) + DW_AT_ranges (0x00000000 + [0x000000000680fe04, 0x000000000680fe16) + [0x000000000680fe1c, 0x000000000680fe20)) + DW_AT_name ("../sysdeps/x86_64/crti.S") + DW_AT_comp_dir ("/home/abuild/rpmbuild/BUILD/glibc-2.31/csu") + DW_AT_producer ("GNU AS 2.43.1") + DW_AT_language (DW_LANG_Mips_Assembler) +0x000000a6: Compile Unit: length = 0x0000445e, format = DWARF32, version = 0x0005, unit_type = DW_UT_compile, abbr_offset = 0x0066, addr_size = 0x08 (next unit at 0x00004508) + +0x000000b2: DW_TAG_compile_unit + DW_AT_producer ("MongoDB clang version 19.1.7 (https://x-access-token:ghs_abc123@github.com/10gen/toolchain-builder.git 868b3c714c67f4f245623d2f772d0fac95d936a2)") + DW_AT_language (DW_LANG_C_plus_plus_14) + DW_AT_name ("src/mongo/db/mongod.cpp") + DW_AT_str_offsets_base (0x00000008) + DW_AT_stmt_list (0x000000e2) + DW_AT_comp_dir (".") + DW_AT_low_pc (0x0000000000000000) + DW_AT_ranges (indexed (0x0) rangelist = 0x00000010 + [0x0000000003b0ddb0, 0x0000000003b0ddc0) + [0x0000000003b0ddc0, 0x0000000003b0ddc9) + [0x0000000003b0b6ad, 0x0000000003b0b6d4) + [0x0000000003b0b6e0, 0x0000000003b0b71f)) + DW_AT_addr_base (0x00000008) + DW_AT_rnglists_base (0x0000000c) + DW_AT_loclists_base (0x0000000c) +""" + + self.assertEqual(get_dwarf_version(dwarf_dump), 5) + + +if __name__ == "__main__": + unittest.main()