This file is indexed.

/usr/lib/python3/dist-packages/diffoscope/comparators/macho.py is in diffoscope 93ubuntu1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# -*- coding: utf-8 -*-
#
# diffoscope: in-depth comparison of files, archives, and directories
#
# Copyright © 2014-2015 Jérémy Bobbio <lunar@debian.org>
# Copyright © 2015 Clemens Lang <cal@macports.org>
#
# diffoscope is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# diffoscope is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with diffoscope.  If not, see <https://www.gnu.org/licenses/>.

import re
import subprocess

from diffoscope.tools import tool_required
from diffoscope.difference import Difference

from .utils.file import File
from .utils.command import Command


class Otool(Command):
    def __init__(self, path, arch, *args, **kwargs):
        self._path = path
        self._arch = arch
        super().__init__(path, *args, **kwargs)

    @tool_required('otool')
    def cmdline(self):
        return ['otool'] + self.otool_options() + [self.path]

    def otool_options(self):
        return ['-arch', self._arch]

    def filter(self, line):
        # Strip filename
        prefix = '{}:'.format(self._path)
        if line.decode('utf-8', 'ignore').index(prefix) == 0:
            return line[len(prefix):].strip()
        return line


class OtoolHeaders(Otool):
    def otool_options(self):
        return super().otool_options() + ['-h']


class OtoolLibraries(Otool):
    def otool_options(self):
        return super().otool_options() + ['-L']


class OtoolDisassemble(Otool):
    def otool_options(self):
        return super().otool_options() + ['-tdvV']


class OtoolDisassembleInternal(Otool):
    def otool_options(self):
        return super().otool_options() + ['-tdvVQ']


class MachoFile(File):
    DESCRIPTION = "MacOS binaries"
    FILE_TYPE_RE = re.compile(r'^Mach-O ')
    RE_EXTRACT_ARCHS = re.compile(r'^(?:Architectures in the fat file: .* are|Non-fat file: .* is architecture): (.*)$')

    @staticmethod
    @tool_required('lipo')
    def get_arch_from_macho(path):
        lipo_output = subprocess.check_output(['lipo', '-info', path]).decode('utf-8')
        lipo_match = MachoFile.RE_EXTRACT_ARCHS.match(lipo_output)
        if lipo_match is None:
            raise ValueError('lipo -info on Mach-O file %s did not produce expected output. Output was: %s' % path, lipo_output)
        return lipo_match.group(1).split()

    def compare_details(self, other, source=None):
        differences = []
        # Check for fat binaries, trigger a difference if the architectures differ
        my_archs = MachoFile.get_arch_from_macho(self.path)
        other_archs = MachoFile.get_arch_from_macho(other.path)

        differences.append(Difference.from_text('\n'.join(my_archs),
                                                '\n'.join(other_archs),
                                                self.name, other.name, source='architectures'))

        # Compare common architectures for differences
        for common_arch in set(my_archs) & set(other_archs):
            differences.append(Difference.from_command(OtoolHeaders, self.path, other.path, command_args=[common_arch],
                                                       comment="Mach-O headers for architecture %s" % common_arch))
            differences.append(Difference.from_command(OtoolLibraries, self.path, other.path, command_args=[common_arch],
                                                       comment="Mach-O load commands for architecture %s" % common_arch))

            x = Difference.from_command(
                OtoolDisassemble,
                self.path,
                other.path,
                command_args=[common_arch],
                comment="Code for architecture %s" % common_arch,
            )
            differences.append(x)

            # If the LLVM disassembler does not work, try the internal one.
            if x is None:
                differences.append(Difference.from_command(
                    OtoolDisassembleInternal,
                    self.path,
                    other.path,
                    command_args=[common_arch],
                    comment="Code for architecture %s (internal disassembler)" % common_arch,
                ))

        return differences