From e972a570d18f32210fa9d4bcfc615e244ad54555 Mon Sep 17 00:00:00 2001 From: Ronan Dunklau Date: Mon, 8 Aug 2022 16:50:55 +0200 Subject: [PATCH] Supplementary object files (#426) * Recognize DW_FORM_ref_udata as a reference type. References to other DIEs can also be implemented with a form DW_FORM_ref_udata, for using the ULEB128 encoding * Add support for DWARF supplementary object files. --- elftools/common/py3compat.py | 1 + elftools/dwarf/compileunit.py | 8 +- elftools/dwarf/die.py | 12 ++- elftools/dwarf/dwarfinfo.py | 32 +++++- elftools/dwarf/structs.py | 20 +++- elftools/elf/elffile.py | 75 +++++++++++-- elftools/elf/structs.py | 5 + test/test_refaddr_bitness.py | 4 +- test/test_supplementary_object_files.py | 101 ++++++++++++++++++ .../test_debugsup.common | Bin 0 -> 3239 bytes test/testfiles_for_unittests/test_debugsup1 | Bin 0 -> 18576 bytes test/testfiles_for_unittests/test_debugsup2 | Bin 0 -> 18576 bytes .../test_gnudebugaltlink.common | Bin 0 -> 3255 bytes .../test_gnudebugaltlink1 | Bin 0 -> 18608 bytes .../test_gnudebugaltlink2 | Bin 0 -> 18608 bytes 15 files changed, 244 insertions(+), 14 deletions(-) create mode 100644 test/test_supplementary_object_files.py create mode 100644 test/testfiles_for_unittests/test_debugsup.common create mode 100755 test/testfiles_for_unittests/test_debugsup1 create mode 100755 test/testfiles_for_unittests/test_debugsup2 create mode 100644 test/testfiles_for_unittests/test_gnudebugaltlink.common create mode 100755 test/testfiles_for_unittests/test_gnudebugaltlink1 create mode 100755 test/testfiles_for_unittests/test_gnudebugaltlink2 diff --git a/elftools/common/py3compat.py b/elftools/common/py3compat.py index e3980b2..46bbfb3 100644 --- a/elftools/common/py3compat.py +++ b/elftools/common/py3compat.py @@ -13,6 +13,7 @@ PY3 = sys.version_info[0] == 3 if PY3: import io from pathlib import Path + StringIO = io.StringIO BytesIO = io.BytesIO diff --git a/elftools/dwarf/compileunit.py b/elftools/dwarf/compileunit.py index f1884e2..704dec3 100644 --- a/elftools/dwarf/compileunit.py +++ b/elftools/dwarf/compileunit.py @@ -165,7 +165,7 @@ class CompileUnit(object): sibling = child.attributes["DW_AT_sibling"] if sibling.form in ('DW_FORM_ref1', 'DW_FORM_ref2', 'DW_FORM_ref4', 'DW_FORM_ref8', - 'DW_FORM_ref'): + 'DW_FORM_ref', 'DW_FORM_ref_udata'): cur_offset = sibling.value + self.cu_offset elif sibling.form == 'DW_FORM_ref_addr': cur_offset = sibling.value @@ -198,10 +198,14 @@ class CompileUnit(object): """ Given a DIE, this yields it with its subtree including null DIEs (child list terminators). """ + # If the die is an imported unit, replace it with what it refers to if + # we can + if die.tag == 'DW_TAG_imported_unit' and self.dwarfinfo.supplementary_dwarfinfo: + die = die.get_DIE_from_attribute('DW_AT_import') yield die if die.has_children: for c in die.iter_children(): - for d in self._iter_DIE_subtree(c): + for d in die.cu._iter_DIE_subtree(c): yield d yield die._terminator diff --git a/elftools/dwarf/die.py b/elftools/dwarf/die.py index 76f2096..b26f8a1 100755 --- a/elftools/dwarf/die.py +++ b/elftools/dwarf/die.py @@ -108,7 +108,7 @@ class DIE(object): """ attr = self.attributes[name] if attr.form in ('DW_FORM_ref1', 'DW_FORM_ref2', 'DW_FORM_ref4', - 'DW_FORM_ref8', 'DW_FORM_ref'): + 'DW_FORM_ref8', 'DW_FORM_ref', 'DW_FORM_ref_udata'): refaddr = self.cu.cu_offset + attr.raw_value return self.cu.get_DIE_from_refaddr(refaddr) elif attr.form in ('DW_FORM_ref_addr'): @@ -116,7 +116,10 @@ class DIE(object): elif attr.form in ('DW_FORM_ref_sig8'): # Implement search type units for matching signature raise NotImplementedError('%s (type unit by signature)' % attr.form) - elif attr.form in ('DW_FORM_ref_sup4', 'DW_FORM_ref_sup8'): + elif attr.form in ('DW_FORM_ref_sup4', 'DW_FORM_ref_sup8', 'DW_FORM_GNU_ref_alt'): + if self.dwarfinfo.supplementary_dwarfinfo: + return self.dwarfinfo.supplementary_dwarfinfo.get_DIE_from_refaddr(attr.raw_value) + # FIXME: how to distinguish supplementary files from dwo ? raise NotImplementedError('%s to dwo' % attr.form) else: raise DWARFError('%s is not a reference class form attribute' % attr) @@ -275,6 +278,11 @@ class DIE(object): elif form == 'DW_FORM_line_strp': with preserve_stream_pos(self.stream): value = self.dwarfinfo.get_string_from_linetable(raw_value) + elif form in ('DW_FORM_GNU_strp_alt', 'DW_FORM_strp_sup'): + if self.dwarfinfo.supplementary_dwarfinfo: + return self.dwarfinfo.supplementary_dwarfinfo.get_string_from_table(raw_value) + else: + value = raw_value elif form == 'DW_FORM_flag': value = not raw_value == 0 elif form == 'DW_FORM_flag_present': diff --git a/elftools/dwarf/dwarfinfo.py b/elftools/dwarf/dwarfinfo.py index 22cd0eb..4edc7cd 100644 --- a/elftools/dwarf/dwarfinfo.py +++ b/elftools/dwarf/dwarfinfo.py @@ -79,7 +79,10 @@ class DWARFInfo(object): debug_str_offsets_sec, debug_line_str_sec, debug_loclists_sec, - debug_rnglists_sec): # Not parsed for now + debug_rnglists_sec, + debug_sup_sec, + gnu_debugaltlink_sec + ): """ config: A DwarfConfig object @@ -105,6 +108,13 @@ class DWARFInfo(object): self.debug_pubnames_sec = debug_pubnames_sec self.debug_loclists_sec = debug_loclists_sec self.debug_rnglists_sec = debug_rnglists_sec + self.debug_sup_sec = debug_sup_sec + self.gnu_debugaltlink_sec = gnu_debugaltlink_sec + + # Sets the supplementary_dwarfinfo to None. Client code can set this + # to something else, typically a DWARFInfo file read from an ELFFile + # which path is stored in the debug_sup_sec or gnu_debugaltlink_sec. + self.supplementary_dwarfinfo = None # This is the DWARFStructs the context uses, so it doesn't depend on # DWARF format and address_size (these are determined per CU) - set them @@ -507,6 +517,11 @@ class DWARFInfo(object): replace_value(data, field.content_type, self.get_string_from_linetable) elif field.form == 'DW_FORM_strp': replace_value(data, field.content_type, self.get_string_from_table) + elif field.form in ('DW_FORM_strp_sup', 'DW_FORM_GNU_strp_alt'): + if self.supplementary_dwarfinfo: + replace_value(data, field.content_type, self.supplementary_dwarfinfo.get_string_fromtable) + else: + replace_value(data, field.content_type, lambda x: str(x)) elif field.form in ('DW_FORM_strp_sup', 'DW_FORM_strx', 'DW_FORM_strx1', 'DW_FORM_strx2', 'DW_FORM_strx3', 'DW_FORM_strx4'): raise NotImplementedError() @@ -536,3 +551,18 @@ class DWARFInfo(object): program_start_offset=self.debug_line_sec.stream.tell(), program_end_offset=end_offset) + def parse_debugsupinfo(self): + """ + Extract a filename from either .debug_sup or .gnu_debualtlink sections. + """ + if self.debug_sup_sec is not None: + self.debug_sup_sec.stream.seek(0) + suplink = self.structs.Dwarf_debugsup.parse_stream(self.debug_sup_sec.stream) + if suplink.is_supplementary == 0: + return suplink.sup_filename + if self.gnu_debugaltlink_sec is not None: + self.gnu_debugaltlink_sec.stream.seek(0) + suplink = self.structs.Dwarf_debugaltlink.parse_stream(self.gnu_debugaltlink_sec.stream) + return suplink.sup_filename + return None + diff --git a/elftools/dwarf/structs.py b/elftools/dwarf/structs.py index 798f690..1a5ae45 100644 --- a/elftools/dwarf/structs.py +++ b/elftools/dwarf/structs.py @@ -13,7 +13,7 @@ from ..construct import ( SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64, Adapter, Struct, ConstructError, If, Enum, Array, PrefixedArray, CString, Embed, StaticField, IfThenElse, Construct, Rename, Sequence, - Switch, Value + String, Switch, Value ) from ..common.construct_utils import (RepeatUntilExcluding, ULEB128, SLEB128, StreamOffset) @@ -146,6 +146,9 @@ class DWARFStructs(object): self._create_loclists_parsers() self._create_rnglists_parsers() + self._create_debugsup() + self._create_gnu_debugaltlink() + def _create_initial_length(self): def _InitialLength(name): # Adapts a Struct that parses forward a full initial length field. @@ -191,6 +194,18 @@ class DWARFStructs(object): If(lambda ctx: ctx['form'] == 'DW_FORM_implicit_const', self.Dwarf_sleb128('value'))))) + def _create_debugsup(self): + # We don't care about checksums, for now. + self.Dwarf_debugsup = Struct('Elf_debugsup', + self.Dwarf_int16('version'), + self.Dwarf_uint8('is_supplementary'), + CString('sup_filename')) + + def _create_gnu_debugaltlink(self): + self.Dwarf_debugaltlink = Struct('Elf_debugaltlink', + CString("sup_filename"), + String("sup_checksum", length=20)) + def _create_dw_form(self): self.Dwarf_dw_form = dict( DW_FORM_addr=self.Dwarf_target_addr(''), @@ -215,6 +230,7 @@ class DWARFStructs(object): DW_FORM_string=CString(''), DW_FORM_strp=self.Dwarf_offset(''), + DW_FORM_strp_sup=self.Dwarf_offset(''), DW_FORM_line_strp=self.Dwarf_offset(''), DW_FORM_strx1=self.Dwarf_uint8(''), DW_FORM_strx2=self.Dwarf_uint16(''), @@ -226,7 +242,9 @@ class DWARFStructs(object): DW_FORM_ref1=self.Dwarf_uint8(''), DW_FORM_ref2=self.Dwarf_uint16(''), DW_FORM_ref4=self.Dwarf_uint32(''), + DW_FORM_ref_sup4=self.Dwarf_uint32(''), DW_FORM_ref8=self.Dwarf_uint64(''), + DW_FORM_ref_sup8=self.Dwarf_uint64(''), DW_FORM_ref_udata=self.Dwarf_uleb128(''), DW_FORM_ref_addr=self.Dwarf_target_addr('') if self.dwarf_version == 2 else self.Dwarf_offset(''), diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py index bdda624..e4ee5e9 100644 --- a/elftools/elf/elffile.py +++ b/elftools/elf/elffile.py @@ -7,6 +7,7 @@ # This code is in the public domain #------------------------------------------------------------------------------- import io +import os import struct import zlib @@ -46,6 +47,12 @@ class ELFFile(object): """ Creation: the constructor accepts a stream (file-like object) with the contents of an ELF file. + Optionally, a stream_loader function can be passed as the second + argument. This stream_loader function takes a relative file path to + load a supplementary object file, and returns a stream suitable for + creating a new ELFFile. Currently, the only such relative file path is + obtained from the supplementary object files. + Accessible attributes: stream: @@ -69,7 +76,7 @@ class ELFFile(object): e_ident_raw: the raw e_ident field of the header """ - def __init__(self, stream): + def __init__(self, stream, stream_loader=None): self.stream = stream self._identify_file() self.structs = ELFStructs( @@ -88,6 +95,23 @@ class ELFFile(object): self._section_header_stringtable = \ self._get_section_header_stringtable() self._section_name_map = None + self.stream_loader = stream_loader + + @classmethod + def load_from_path(cls, path): + """Takes a path to a file on the local filesystem, and returns an + ELFFile from it, setting up a correct stream_loader relative to the + original file. + """ + base_directory = os.path.dirname(path) + def loader(elf_path): + # FIXME: use actual path instead of str/bytes + if not os.path.isabs(elf_path): + elf_path = os.path.join(base_directory, + elf_path) + return open(elf_path, 'rb') + stream = open(path, 'rb') + return ELFFile(stream, loader) def num_sections(self): """ Number of sections in the file @@ -203,12 +227,15 @@ class ELFFile(object): self.get_section_by_name('.zdebug_info') or self.get_section_by_name('.eh_frame')) - def get_dwarf_info(self, relocate_dwarf_sections=True): + def get_dwarf_info(self, relocate_dwarf_sections=True, follow_links=True): """ Return a DWARFInfo object representing the debugging information in this file. If relocate_dwarf_sections is True, relocations for DWARF sections are looked up and applied. + + If follow_links is True, we will try to load the supplementary + object file (if any), and use it to resolve references and imports. """ # Expect that has_dwarf_info was called, so at least .debug_info is # present. @@ -219,8 +246,8 @@ class ELFFile(object): '.debug_loc', '.debug_ranges', '.debug_pubtypes', '.debug_pubnames', '.debug_addr', '.debug_str_offsets', '.debug_line_str', - '.debug_loclists', '.debug_rnglists') - + '.debug_loclists', '.debug_rnglists', + '.debug_sup', '.gnu_debugaltlink') compressed = bool(self.get_section_by_name('.zdebug_info')) if compressed: @@ -234,7 +261,7 @@ class ELFFile(object): debug_loc_sec_name, debug_ranges_sec_name, debug_pubtypes_name, debug_pubnames_name, debug_addr_name, debug_str_offsets_name, debug_line_str_name, debug_loclists_sec_name, debug_rnglists_sec_name, - eh_frame_sec_name) = section_names + debug_sup_name, gnu_debugaltlink_name, eh_frame_sec_name) = section_names debug_sections = {} for secname in section_names: @@ -249,7 +276,11 @@ class ELFFile(object): dwarf_section = self._decompress_dwarf_section(dwarf_section) debug_sections[secname] = dwarf_section - return DWARFInfo( + # Lookup if we have any of the .gnu_debugaltlink (GNU proprietary + # implementation) or .debug_sup sections, referencing a supplementary + # DWARF file + + dwarfinfo = DWARFInfo( config=DwarfConfig( little_endian=self.little_endian, default_address_size=self.elfclass // 8, @@ -269,8 +300,29 @@ class ELFFile(object): debug_str_offsets_sec=debug_sections[debug_str_offsets_name], debug_line_str_sec=debug_sections[debug_line_str_name], debug_loclists_sec=debug_sections[debug_loclists_sec_name], - debug_rnglists_sec=debug_sections[debug_rnglists_sec_name] + debug_rnglists_sec=debug_sections[debug_rnglists_sec_name], + debug_sup_sec=debug_sections[debug_sup_name], + gnu_debugaltlink_sec=debug_sections[gnu_debugaltlink_name] ) + if follow_links: + dwarfinfo.supplementary_dwarfinfo = self.get_supplementary_dwarfinfo(dwarfinfo) + return dwarfinfo + + + def get_supplementary_dwarfinfo(self, dwarfinfo): + """ + Read supplementary dwarfinfo, from either the standared .debug_sup + section or the GNU proprietary .gnu_debugaltlink. + """ + supfilepath = dwarfinfo.parse_debugsupinfo() + if supfilepath is not None and self.stream_loader is not None: + stream = self.stream_loader(supfilepath) + supelffile = ELFFile(stream) + dwarf_info = supelffile.get_dwarf_info() + stream.close() + return dwarf_info + return None + def has_ehabi_info(self): """ Check whether this file appears to have arm exception handler index table. @@ -765,3 +817,12 @@ class ELFFile(object): ) return section._replace(stream=uncompressed_stream, size=size) + + def close(self): + self.stream.close() + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.close() diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py index b437eec..74ea54d 100644 --- a/elftools/elf/structs.py +++ b/elftools/elf/structs.py @@ -380,6 +380,11 @@ class ELFStructs(object): self.Elf_word('abi_tiny'), ) + def _create_gnu_debugaltlink(self): + self.Elf_debugaltlink = Struct('Elf_debugaltlink', + CString("sup_filename"), + String("sup_checksum", length=20)) + def _create_gnu_property(self): # Structure of GNU property notes is documented in # https://github.com/hjl-tools/linux-abi/wiki/linux-abi-draft.pdf diff --git a/test/test_refaddr_bitness.py b/test/test_refaddr_bitness.py index c92e442..472a595 100644 --- a/test/test_refaddr_bitness.py +++ b/test/test_refaddr_bitness.py @@ -48,7 +48,9 @@ class TestRefAddrOnDWARFv2With64BitTarget(unittest.TestCase): debug_str_offsets_sec=None, debug_line_str_sec=None, debug_loclists_sec = None, - debug_rnglists_sec = None + debug_rnglists_sec = None, + debug_sup_sec = None, + gnu_debugaltlink_sec = None ) CUs = [cu for cu in di.iter_CUs()] diff --git a/test/test_supplementary_object_files.py b/test/test_supplementary_object_files.py new file mode 100644 index 0000000..ee01a2d --- /dev/null +++ b/test/test_supplementary_object_files.py @@ -0,0 +1,101 @@ +# The test_gnudebugaltlink* and test_debugsup* files have been generated as +# follows: +# $ cat test_sup.c +# int main(int argc, char** argv) +# { +# return argc; +# } +# +# $ gcc test_sup.c -o test_debugsup1 +# $ gcc test_sup.c -o test_debugsup2 +# $ dwz test_debugsup1 test_debugsup2 -m test_debugsup.common --dwarf-5 +# +# $ gcc test_sup.c -o test_gnudebugaltlink1 +# $ gcc test_sup.c -o test_gnudebugaltlink2 +# $ dwz test_gnudebugaltlink1 test_gnudebugaltlink2 -m test_gnudebugaltlink.common + +import unittest +import os + +from elftools.elf.elffile import ELFFile + +class TestDWARFSupplementaryObjects(unittest.TestCase): + + def test_gnudebugaltlink_no_followlinks(self): + path = os.path.join('test', 'testfiles_for_unittests', + 'test_gnudebugaltlink1') + with open(path, 'rb') as f: + elffile = ELFFile(f) + # Check that we don't have a supplementary_dwarfinfo + dwarfinfo = elffile.get_dwarf_info(follow_links=False) + self.assertIsNone(dwarfinfo.supplementary_dwarfinfo) + # Check that imported units are present + self.assertTrue(any(die.tag == 'DW_TAG_imported_unit' + for cu in dwarfinfo.iter_CUs() + for die in cu.iter_DIEs())) + # Check that DW_FORM_GNU_strp_alt keep their raw_value. + for cu in dwarfinfo.iter_CUs(): + for die in cu.iter_DIEs(): + attrs = die.attributes + if ('DW_AT_name' in attrs and + attrs['DW_AT_name'].form == 'DW_FORM_GNU_strp_alt'): + self.assertEqual(attrs['DW_AT_name'].value, + attrs['DW_AT_name'].raw_value) + + def test_gnudebugaltlink_followlinks(self): + base_dir = os.path.join(b'test', b'testfiles_for_unittests') + path = os.path.join(base_dir, b'test_gnudebugaltlink1') + with ELFFile.load_from_path(path) as elffile: + # Check that we do have a supplementary_dwarfinfo + dwarfinfo = elffile.get_dwarf_info() + self.assertIsNotNone(dwarfinfo.supplementary_dwarfinfo) + # Check that imported units are replaced by what they refer to. + self.assertTrue(all(die.tag != 'DW_TAG_imported_unit' + for cu in dwarfinfo.iter_CUs() + for die in cu.iter_DIEs())) + # Check that DW_FORM_GNU_strp_alt get a proper reference + for cu in dwarfinfo.iter_CUs(): + for die in cu.iter_DIEs(): + attrs = die.attributes + if ('DW_AT_name' in attrs and attrs['DW_AT_name'].form == + 'DW_FORM_GNU_strp_alt'): + self.assertIsInstance(attrs['DW_AT_name'].value, bytes) + + def test_debugsup_no_followlinks(self): + path = os.path.join('test', 'testfiles_for_unittests', + 'test_debugsup1') + with ELFFile.load_from_path(path) as elffile: + # Check that we don't have a supplementary_dwarfinfo + dwarfinfo = elffile.get_dwarf_info(follow_links=False) + self.assertIsNone(dwarfinfo.supplementary_dwarfinfo) + # Check that imported units are present + self.assertTrue(any(die.tag == 'DW_TAG_imported_unit' + for cu in dwarfinfo.iter_CUs() + for die in cu.iter_DIEs())) + # Check that DW_FORM_GNU_strp_alt keep their raw_value. + for cu in dwarfinfo.iter_CUs(): + for die in cu.iter_DIEs(): + attrs = die.attributes + if ('DW_AT_name' in attrs and + attrs['DW_AT_name'].form == 'DW_FORM_strp_sup'): + self.assertEqual(attrs['DW_AT_name'].value, + attrs['DW_AT_name'].raw_value) + + def test_debugsup_followlinks(self): + base_dir = os.path.join(b'test', b'testfiles_for_unittests') + path = os.path.join(base_dir, b'test_debugsup1') + with ELFFile.load_from_path(path) as elffile: + # Check that we do have a supplementary_dwarfinfo + dwarfinfo = elffile.get_dwarf_info() + self.assertIsNotNone(dwarfinfo.supplementary_dwarfinfo) + # Check that imported units are replaced by what they refer to. + self.assertTrue(all(die.tag != 'DW_TAG_imported_unit' + for cu in dwarfinfo.iter_CUs() + for die in cu.iter_DIEs())) + # Check that DW_FORM_GNU_strp_alt get a proper reference + for cu in dwarfinfo.iter_CUs(): + for die in cu.iter_DIEs(): + attrs = die.attributes + if ('DW_AT_name' in attrs and attrs['DW_AT_name'].form == + 'DW_FORM_strp_sup'): + self.assertIsInstance(attrs['DW_AT_name'].value, bytes) diff --git a/test/testfiles_for_unittests/test_debugsup.common b/test/testfiles_for_unittests/test_debugsup.common new file mode 100644 index 0000000000000000000000000000000000000000..d9d9c9aea22d270539348c86338a502e9f74adba GIT binary patch literal 3239 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 literal 0 HcmV?d00001 diff --git a/test/testfiles_for_unittests/test_debugsup2 b/test/testfiles_for_unittests/test_debugsup2 new file mode 100755 index 0000000000000000000000000000000000000000..bedc082ee4f78ea3b1f753a18d230d48544128c3 GIT binary patch literal 18576 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 literal 0 HcmV?d00001 diff --git a/test/testfiles_for_unittests/test_gnudebugaltlink.common b/test/testfiles_for_unittests/test_gnudebugaltlink.common new file mode 100644 index 0000000000000000000000000000000000000000..1bc21c9686f154f59ea6c2d086d3b8e006099fd4 GIT binary patch literal 3255 zcmbtWYit}>6~1%l&SPiR>&5r-ss)b4vR1rlbO#-44ipoO;qEwV~ zW?zm8@PjMOz2AACbMLt`^H^p7UdnN#JvcH&x>TD>$TyTO-bE&W*hM5F5(X#-4-e12 z*+b;q6L-J8d+jOy>wo+1{3rK)K>k$u=8wJxLV@rysE`4iR8IaUg@sDL0+Gt3cX5%W zpX0)b=!_nQi5nfTNN01#{?WPcu~+xiaB zWdQumPtMTX0}x33sqhs_a(UQy@vQO+r9?PM)6VO(XS9bXC#m*2<)1;*H>vU_)z&D# z1)K`!sB(^K7byQU_!cfv0IBU8Bl1s(nOL-v=ryeRPJ;EkY#e?@1&9;Xiuc z5om4z{7TnzX9bqK0IJf*eWyj42sfy5gKDqv{o5eYki5*@v!X0MjC=+8n~Crmue`=VJ)JX6jy?IKgoQ0+2PegX9} z>W6JNS_E)C-g=*J9%4?r6WtC}92+C7TJ1!_MFzuwEyu`HU1m$N;`<9@*4eS%71F4DlDW$2l%5y(fGu$cG@AOA3Hb19)Fu zg&l-(Sv?_=^wCwZXSA23ALmX0kVyJC_bdROqGgDNBTlqSU~!q#x{Wx{ZTOaJ&dy4|1w{uliYahsuEx9Uy$BNzMSt_W`*R8jmrK z&rGSRI@8}(7Dfpwi9JmlVFySjRH%UCkS{0v5ea=Go$3Q0tzaWEMpJr;IwGS?y`8A) zl*(sdGte5PJtN@01pYF8%^V>B@_X0in1vm>6T%OH+NKsi$%7E>Gf8%RE#p>!xmL1C zPMB)(1jVsgmNG~GEGtM<0NW8D=AelXg!Ut_ibmBbcz$FT zO(N-fT-MQG+c;_4>MP^-bO{5gj@nqcD{;Is2q1y6@d^AkQT4?B&5gAE&d&b7{W8=lK;?{g&*$B+~B$QMr zZwD%hJ$tfddv@TM`9dvUm>bU*;D{z`UJO=+C0HkRz~Mnd*g$%Iq2WdV>=n~)M2_!; zKtQ49;ezQJVZG1@;Dk(+fWTZ@M^7%rt_#d%JE++O!*vTLm`8>ep^w0iJ!q5~WEj;u zK3m@W0FnxP4-&)_On-Sf@sGL%I|w`<1Puo>yk*G94GYV@WxJD(=R}U-7VH(`MZA{BS3yj_3D4=mzhc*~Egu1!2+873Wj9GV9DQjd&U zx4|rz=(~O2?Q$Hii*0`$5d+4EORj&!@s@m~^ka4apmig3CtOc>M$jO!7dkc1w(@4( z2$~M?E+ocHklc-qk5(PCbNxkp=2h4>u1DDaa4Xiqv2uqy0SHn#bF=>|q-1B11szMK0_6jLlb~Ua60hh6bjcPTpA8k|kDr{r$*oMo73AgrN DC;haK literal 0 HcmV?d00001 diff --git a/test/testfiles_for_unittests/test_gnudebugaltlink1 b/test/testfiles_for_unittests/test_gnudebugaltlink1 new file mode 100755 index 0000000000000000000000000000000000000000..0374b5d1298bb5c609f20e22e08b5f1f07ac4f6a GIT binary patch literal 18608 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 FzX6Jm-4Fl( literal 0 HcmV?d00001 diff --git a/test/testfiles_for_unittests/test_gnudebugaltlink2 b/test/testfiles_for_unittests/test_gnudebugaltlink2 new file mode 100755 index 0000000000000000000000000000000000000000..0374b5d1298bb5c609f20e22e08b5f1f07ac4f6a GIT binary patch literal 18608 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 FzX6Jm-4Fl( literal 0 HcmV?d00001 -- 2.30.2