xref: /xnu-8796.121.2/tools/lldbmacros/macho.py (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
1*c54f35caSApple OSS Distributionsfrom __future__ import absolute_import, division, print_function
2*c54f35caSApple OSS Distributions
3*c54f35caSApple OSS Distributionsfrom builtins import range
4*c54f35caSApple OSS Distributionsfrom builtins import object
5*c54f35caSApple OSS Distributions
6*c54f35caSApple OSS Distributionsimport macholib
7*c54f35caSApple OSS Distributionsfrom macholib import MachO as macho
8*c54f35caSApple OSS Distributionsfrom collections import namedtuple
9*c54f35caSApple OSS Distributionsimport six
10*c54f35caSApple OSS Distributionsimport uuid
11*c54f35caSApple OSS Distributionsimport sys
12*c54f35caSApple OSS Distributions
13*c54f35caSApple OSS Distributions
14*c54f35caSApple OSS Distributions#
15*c54f35caSApple OSS Distributions# Defines segment/section descriptions that can be used by external users
16*c54f35caSApple OSS Distributions# like kext management to keep track about memory layout. To avoid the need
17*c54f35caSApple OSS Distributions# to keep full Mach-O instance around.
18*c54f35caSApple OSS Distributions#
19*c54f35caSApple OSS Distributions
20*c54f35caSApple OSS DistributionsMachOSegment = namedtuple(
21*c54f35caSApple OSS Distributions    'MachOSegment',
22*c54f35caSApple OSS Distributions    'name vmaddr vmsize fileoff filesize sections'
23*c54f35caSApple OSS Distributions)
24*c54f35caSApple OSS Distributions
25*c54f35caSApple OSS DistributionsMachOSection = namedtuple(
26*c54f35caSApple OSS Distributions    'MachOSection',
27*c54f35caSApple OSS Distributions    'sectname addr size fileoff'
28*c54f35caSApple OSS Distributions)
29*c54f35caSApple OSS Distributions
30*c54f35caSApple OSS Distributions
31*c54f35caSApple OSS Distributions#
32*c54f35caSApple OSS Distributions# The Mach-O library loads data for each section in a Mach-O.
33*c54f35caSApple OSS Distributions# This breaks our macros in few ways:
34*c54f35caSApple OSS Distributions#   - It is slow and no one is really using it.
35*c54f35caSApple OSS Distributions#   - File offsets in fileset KC points outside of the file window reported
36*c54f35caSApple OSS Distributions#     by OSkext API.
37*c54f35caSApple OSS Distributions#
38*c54f35caSApple OSS Distributions# Until macholib gets some optin to avoid reading section data we have to
39*c54f35caSApple OSS Distributions# patch it here.
40*c54f35caSApple OSS Distributions#
41*c54f35caSApple OSS Distributions# !!! Note. This works only with the latest lib 1.15.1 !!!
42*c54f35caSApple OSS Distributions
43*c54f35caSApple OSS Distributionsif macholib.__version__ == "1.15.2":
44*c54f35caSApple OSS Distributions    from macholib.mach_o import (
45*c54f35caSApple OSS Distributions        LC_ID_DYLIB,
46*c54f35caSApple OSS Distributions        LC_REGISTRY,
47*c54f35caSApple OSS Distributions        LC_SEGMENT,
48*c54f35caSApple OSS Distributions        LC_SEGMENT_64,
49*c54f35caSApple OSS Distributions        S_ZEROFILL,
50*c54f35caSApple OSS Distributions        load_command,
51*c54f35caSApple OSS Distributions        section,
52*c54f35caSApple OSS Distributions        section_64,
53*c54f35caSApple OSS Distributions    )
54*c54f35caSApple OSS Distributions    from macholib.ptypes import sizeof
55*c54f35caSApple OSS Distributions    from macholib.util import fileview
56*c54f35caSApple OSS Distributions
57*c54f35caSApple OSS Distributions
58*c54f35caSApple OSS Distributions    # !!! This is the actual patch for macholib 1.15.2 !!!
59*c54f35caSApple OSS Distributions    #
60*c54f35caSApple OSS Distributions    #   1. MemMachOHeader subclasses macho.MachOHeader
61*c54f35caSApple OSS Distributions    #   2. Overloaded load() method is copy/paste of the original load() with
62*c54f35caSApple OSS Distributions    #      small patch added that disables section contents loading.
63*c54f35caSApple OSS Distributions    #   3. The new MemMachOHeader is injected back into library and used
64*c54f35caSApple OSS Distributions    #      in place of macho.MachOHeader.
65*c54f35caSApple OSS Distributions    #
66*c54f35caSApple OSS Distributions    # This code should not ever exist in the first place. So the plan is to
67*c54f35caSApple OSS Distributions    # remove it when macholib gets improved or abandoned by our own
68*c54f35caSApple OSS Distributions    # implementation.
69*c54f35caSApple OSS Distributions    class MemMachOHeader(macho.MachOHeader):
70*c54f35caSApple OSS Distributions        """ Mach-O header parser that does not try to load section data. """
71*c54f35caSApple OSS Distributions
72*c54f35caSApple OSS Distributions        def load(self, fh):
73*c54f35caSApple OSS Distributions            fh = fileview(fh, self.offset, self.size)
74*c54f35caSApple OSS Distributions            fh.seek(0)
75*c54f35caSApple OSS Distributions
76*c54f35caSApple OSS Distributions            self.sizediff = 0
77*c54f35caSApple OSS Distributions            kw = {"_endian_": self.endian}
78*c54f35caSApple OSS Distributions            header = self.mach_header.from_fileobj(fh, **kw)
79*c54f35caSApple OSS Distributions            self.header = header
80*c54f35caSApple OSS Distributions            # If header.magic != self.MH_MAGIC:
81*c54f35caSApple OSS Distributions            #    raise ValueError("header has magic %08x, expecting %08x" % (
82*c54f35caSApple OSS Distributions            #        header.magic, self.MH_MAGIC))
83*c54f35caSApple OSS Distributions
84*c54f35caSApple OSS Distributions            cmd = self.commands = []
85*c54f35caSApple OSS Distributions
86*c54f35caSApple OSS Distributions            self.filetype = self.get_filetype_shortname(header.filetype)
87*c54f35caSApple OSS Distributions
88*c54f35caSApple OSS Distributions            read_bytes = 0
89*c54f35caSApple OSS Distributions            low_offset = sys.maxsize
90*c54f35caSApple OSS Distributions            for i in range(header.ncmds):
91*c54f35caSApple OSS Distributions                # read the load command
92*c54f35caSApple OSS Distributions                cmd_load = load_command.from_fileobj(fh, **kw)
93*c54f35caSApple OSS Distributions
94*c54f35caSApple OSS Distributions                # read the specific command
95*c54f35caSApple OSS Distributions                klass = LC_REGISTRY.get(cmd_load.cmd, None)
96*c54f35caSApple OSS Distributions                if klass is None:
97*c54f35caSApple OSS Distributions                    raise ValueError("Unknown load command: %d" % (cmd_load.cmd,))
98*c54f35caSApple OSS Distributions                cmd_cmd = klass.from_fileobj(fh, **kw)
99*c54f35caSApple OSS Distributions
100*c54f35caSApple OSS Distributions                if cmd_load.cmd == LC_ID_DYLIB:
101*c54f35caSApple OSS Distributions                    # remember where this command was
102*c54f35caSApple OSS Distributions                    if self.id_cmd is not None:
103*c54f35caSApple OSS Distributions                        raise ValueError("This dylib already has an id")
104*c54f35caSApple OSS Distributions                    self.id_cmd = i
105*c54f35caSApple OSS Distributions
106*c54f35caSApple OSS Distributions                if cmd_load.cmd in (LC_SEGMENT, LC_SEGMENT_64):
107*c54f35caSApple OSS Distributions                    # for segment commands, read the list of segments
108*c54f35caSApple OSS Distributions                    segs = []
109*c54f35caSApple OSS Distributions                    # assert that the size makes sense
110*c54f35caSApple OSS Distributions                    if cmd_load.cmd == LC_SEGMENT:
111*c54f35caSApple OSS Distributions                        section_cls = section
112*c54f35caSApple OSS Distributions                    else:  # LC_SEGMENT_64
113*c54f35caSApple OSS Distributions                        section_cls = section_64
114*c54f35caSApple OSS Distributions
115*c54f35caSApple OSS Distributions                    expected_size = (
116*c54f35caSApple OSS Distributions                        sizeof(klass)
117*c54f35caSApple OSS Distributions                        + sizeof(load_command)
118*c54f35caSApple OSS Distributions                        + (sizeof(section_cls) * cmd_cmd.nsects)
119*c54f35caSApple OSS Distributions                    )
120*c54f35caSApple OSS Distributions                    if cmd_load.cmdsize != expected_size:
121*c54f35caSApple OSS Distributions                        raise ValueError("Segment size mismatch")
122*c54f35caSApple OSS Distributions                    # this is a zero block or something
123*c54f35caSApple OSS Distributions                    # so the beginning is wherever the fileoff of this command is
124*c54f35caSApple OSS Distributions                    if cmd_cmd.nsects == 0:
125*c54f35caSApple OSS Distributions                        if cmd_cmd.filesize != 0:
126*c54f35caSApple OSS Distributions                            low_offset = min(low_offset, cmd_cmd.fileoff)
127*c54f35caSApple OSS Distributions                    else:
128*c54f35caSApple OSS Distributions                        # this one has multiple segments
129*c54f35caSApple OSS Distributions                        for _j in range(cmd_cmd.nsects):
130*c54f35caSApple OSS Distributions                            # read the segment
131*c54f35caSApple OSS Distributions                            seg = section_cls.from_fileobj(fh, **kw)
132*c54f35caSApple OSS Distributions                            # If the segment has a size and is not zero filled
133*c54f35caSApple OSS Distributions                            # then its beginning is the offset of this segment
134*c54f35caSApple OSS Distributions                            not_zerofill = (seg.flags & S_ZEROFILL) != S_ZEROFILL
135*c54f35caSApple OSS Distributions                            if seg.offset > 0 and seg.size > 0 and not_zerofill:
136*c54f35caSApple OSS Distributions                                low_offset = min(low_offset, seg.offset)
137*c54f35caSApple OSS Distributions
138*c54f35caSApple OSS Distributions                            # Do NOT read section data. It is not required and
139*c54f35caSApple OSS Distributions                            # does not work well with filset KC offsets.
140*c54f35caSApple OSS Distributions                            """
141*c54f35caSApple OSS Distributions                            if not_zerofill:
142*c54f35caSApple OSS Distributions                                c = fh.tell()
143*c54f35caSApple OSS Distributions                                fh.seek(seg.offset)
144*c54f35caSApple OSS Distributions                                sd = fh.read(seg.size)
145*c54f35caSApple OSS Distributions                                seg.add_section_data(sd)
146*c54f35caSApple OSS Distributions                                fh.seek(c)
147*c54f35caSApple OSS Distributions                            """
148*c54f35caSApple OSS Distributions                            segs.append(seg)
149*c54f35caSApple OSS Distributions                    # data is a list of segments
150*c54f35caSApple OSS Distributions                    cmd_data = segs
151*c54f35caSApple OSS Distributions
152*c54f35caSApple OSS Distributions                else:
153*c54f35caSApple OSS Distributions                    # data is a raw str
154*c54f35caSApple OSS Distributions                    data_size = cmd_load.cmdsize - sizeof(klass) - sizeof(load_command)
155*c54f35caSApple OSS Distributions                    cmd_data = fh.read(data_size)
156*c54f35caSApple OSS Distributions                cmd.append((cmd_load, cmd_cmd, cmd_data))
157*c54f35caSApple OSS Distributions                read_bytes += cmd_load.cmdsize
158*c54f35caSApple OSS Distributions
159*c54f35caSApple OSS Distributions            # make sure the header made sense
160*c54f35caSApple OSS Distributions            if read_bytes != header.sizeofcmds:
161*c54f35caSApple OSS Distributions                raise ValueError(
162*c54f35caSApple OSS Distributions                    "Read %d bytes, header reports %d bytes"
163*c54f35caSApple OSS Distributions                    % (read_bytes, header.sizeofcmds)
164*c54f35caSApple OSS Distributions                )
165*c54f35caSApple OSS Distributions            self.total_size = sizeof(self.mach_header) + read_bytes
166*c54f35caSApple OSS Distributions            self.low_offset = low_offset
167*c54f35caSApple OSS Distributions
168*c54f35caSApple OSS Distributions
169*c54f35caSApple OSS Distributions    # Patch the library to use our own header class instead.
170*c54f35caSApple OSS Distributions    macho.MachOHeader = MemMachOHeader
171*c54f35caSApple OSS Distributions
172*c54f35caSApple OSS Distributions
173*c54f35caSApple OSS Distributionsclass MemMachO(macho.MachO):
174*c54f35caSApple OSS Distributions    """ Mach-O implementation that accepts I/O stream instead of file. """
175*c54f35caSApple OSS Distributions
176*c54f35caSApple OSS Distributions    def __init__(self, file):
177*c54f35caSApple OSS Distributions        """ Creates Mach-O parser on top of provided I/O. """
178*c54f35caSApple OSS Distributions
179*c54f35caSApple OSS Distributions        # Figured out file size from the I/O.
180*c54f35caSApple OSS Distributions        file.seek(0, 2)
181*c54f35caSApple OSS Distributions        size = file.tell()
182*c54f35caSApple OSS Distributions        file.seek(0, 0)
183*c54f35caSApple OSS Distributions
184*c54f35caSApple OSS Distributions        # supports the ObjectGraph protocol
185*c54f35caSApple OSS Distributions        self.graphident = 'mem:%d//'.format(size)
186*c54f35caSApple OSS Distributions        self.filename = 'mem:%d//'.format(size)
187*c54f35caSApple OSS Distributions        self.loader_path = "<no-path>"
188*c54f35caSApple OSS Distributions
189*c54f35caSApple OSS Distributions        # initialized by load
190*c54f35caSApple OSS Distributions        self.fat = None
191*c54f35caSApple OSS Distributions        self.headers = []
192*c54f35caSApple OSS Distributions
193*c54f35caSApple OSS Distributions        self.load(file)
194*c54f35caSApple OSS Distributions
195*c54f35caSApple OSS Distributions    @staticmethod
196*c54f35caSApple OSS Distributions    def make_seg(seg, sects):
197*c54f35caSApple OSS Distributions        """ Constructs MachOSegment from input. """
198*c54f35caSApple OSS Distributions
199*c54f35caSApple OSS Distributions        # Wrap all sections in MachOSection tuple.
200*c54f35caSApple OSS Distributions        segsec = [
201*c54f35caSApple OSS Distributions            MachOSection(
202*c54f35caSApple OSS Distributions                sectname = six.ensure_str(s.segname[:s.segname.find(b'\x00')]),
203*c54f35caSApple OSS Distributions                addr = s.addr,
204*c54f35caSApple OSS Distributions                fileoff = s.offset,
205*c54f35caSApple OSS Distributions                size = s.size
206*c54f35caSApple OSS Distributions            )
207*c54f35caSApple OSS Distributions            for s in sects
208*c54f35caSApple OSS Distributions        ]
209*c54f35caSApple OSS Distributions
210*c54f35caSApple OSS Distributions        # Return MachOSegment
211*c54f35caSApple OSS Distributions        return MachOSegment(
212*c54f35caSApple OSS Distributions            name=six.ensure_str(seg.segname[:seg.segname.find(b'\x00')]),
213*c54f35caSApple OSS Distributions            vmaddr = seg.vmaddr,
214*c54f35caSApple OSS Distributions            vmsize = seg.vmsize,
215*c54f35caSApple OSS Distributions            fileoff = seg.fileoff,
216*c54f35caSApple OSS Distributions            filesize = seg.filesize,
217*c54f35caSApple OSS Distributions            sections = segsec
218*c54f35caSApple OSS Distributions        )
219*c54f35caSApple OSS Distributions
220*c54f35caSApple OSS Distributions    @property
221*c54f35caSApple OSS Distributions    def segments(self):
222*c54f35caSApple OSS Distributions        """ Constructs section/segment descriptors.
223*c54f35caSApple OSS Distributions
224*c54f35caSApple OSS Distributions            Values are cached in an instance attribute.
225*c54f35caSApple OSS Distributions        """
226*c54f35caSApple OSS Distributions        if hasattr(self, '_segments'):
227*c54f35caSApple OSS Distributions            return self._segments
228*c54f35caSApple OSS Distributions
229*c54f35caSApple OSS Distributions        # Wrap all segments/sections into a MachOSegment/MachOSection.
230*c54f35caSApple OSS Distributions        self._segments = [
231*c54f35caSApple OSS Distributions            self.make_seg(seg, sec)
232*c54f35caSApple OSS Distributions            for h in self.headers
233*c54f35caSApple OSS Distributions            for _, seg, sec in h.commands
234*c54f35caSApple OSS Distributions            if isinstance(seg, SEGMENT_TYPES)
235*c54f35caSApple OSS Distributions        ]
236*c54f35caSApple OSS Distributions
237*c54f35caSApple OSS Distributions        return self._segments
238*c54f35caSApple OSS Distributions
239*c54f35caSApple OSS Distributions    @property
240*c54f35caSApple OSS Distributions    def uuid(self):
241*c54f35caSApple OSS Distributions        """ Returns UUID of the Mach-O. """
242*c54f35caSApple OSS Distributions        if hasattr(self, '_uuid'):
243*c54f35caSApple OSS Distributions            return self._uuid
244*c54f35caSApple OSS Distributions
245*c54f35caSApple OSS Distributions        for h in self.headers:
246*c54f35caSApple OSS Distributions            for cmd in h.commands:
247*c54f35caSApple OSS Distributions                # cmds is [(load_command, segment, [sections..])]
248*c54f35caSApple OSS Distributions                (_, segment, _) = cmd
249*c54f35caSApple OSS Distributions                if isinstance(segment, macholib.mach_o.uuid_command):
250*c54f35caSApple OSS Distributions                    self._uuid = str(uuid.UUID(bytes=segment.uuid)).upper()
251*c54f35caSApple OSS Distributions        return self._uuid
252*c54f35caSApple OSS Distributions
253*c54f35caSApple OSS Distributions
254*c54f35caSApple OSS Distributions# some fixups in macholib that are required for kext support
255*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_KEXT_BUNDLE = 0xB
256*c54f35caSApple OSS Distributions
257*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_FILETYPE_NAMES[macholib.mach_o.MH_KEXT_BUNDLE] = "kext bundle"
258*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_FILETYPE_SHORTNAMES[macholib.mach_o.MH_KEXT_BUNDLE] = "kext"
259*c54f35caSApple OSS Distributions
260*c54f35caSApple OSS DistributionsSEGMENT_TYPES = (macholib.mach_o.segment_command_64, macholib.mach_o.segment_command)
261*c54f35caSApple OSS Distributions
262*c54f35caSApple OSS Distributionsif six.PY3:
263*c54f35caSApple OSS Distributions    # Use newer macholib interface on Python 3.
264*c54f35caSApple OSS Distributions    def get_load_command_human_name(lc):
265*c54f35caSApple OSS Distributions        return lc.get_cmd_name()
266*c54f35caSApple OSS Distributionselse:
267*c54f35caSApple OSS Distributions    def get_load_command_human_name(lc):
268*c54f35caSApple OSS Distributions        """ return string name of LC_LOAD_DYLIB => "load_dylib"
269*c54f35caSApple OSS Distributions            "<unknown>" if not found
270*c54f35caSApple OSS Distributions        """
271*c54f35caSApple OSS Distributions        retval = "<unknown>"
272*c54f35caSApple OSS Distributions        if lc.cmd in macho.LC_REGISTRY:
273*c54f35caSApple OSS Distributions            retval = macho.LC_REGISTRY[lc.cmd].__name__
274*c54f35caSApple OSS Distributions            retval = retval.replace("_command", "")
275*c54f35caSApple OSS Distributions        return retval
276*c54f35caSApple OSS Distributions
277*c54f35caSApple OSS Distributions
278*c54f35caSApple OSS Distributionsclass VisualMachoMap(object):
279*c54f35caSApple OSS Distributions    KB_1 = 1024
280*c54f35caSApple OSS Distributions    KB_16 = 16 * 1024
281*c54f35caSApple OSS Distributions    MB_1 = 1 * 1024 * 1024
282*c54f35caSApple OSS Distributions    GB_1 = 1 * 1024 * 1024 * 1024
283*c54f35caSApple OSS Distributions
284*c54f35caSApple OSS Distributions    def __init__(self, name, width=40):
285*c54f35caSApple OSS Distributions        self.name = name
286*c54f35caSApple OSS Distributions        self.width = 40
287*c54f35caSApple OSS Distributions        self.default_side_padding = 2
288*c54f35caSApple OSS Distributions
289*c54f35caSApple OSS Distributions    def get_header_line(self):
290*c54f35caSApple OSS Distributions        return '+' + '-' * (self.width - 2) + '+'
291*c54f35caSApple OSS Distributions
292*c54f35caSApple OSS Distributions    def get_space_line(self):
293*c54f35caSApple OSS Distributions        return '|' + ' ' * (self.width - 2) + '|'
294*c54f35caSApple OSS Distributions
295*c54f35caSApple OSS Distributions    def get_dashed_line(self):
296*c54f35caSApple OSS Distributions        return '|' + '-' * (self.width - 2) + '|'
297*c54f35caSApple OSS Distributions
298*c54f35caSApple OSS Distributions    def get_dotted_line(self):
299*c54f35caSApple OSS Distributions        return '|' + '.' * (self.width - 2) + '|'
300*c54f35caSApple OSS Distributions
301*c54f35caSApple OSS Distributions    def center_text_in_line(self, line, text):
302*c54f35caSApple OSS Distributions        even_length = bool(len(text) % 2 == 0)
303*c54f35caSApple OSS Distributions        if len(text) > len(line) - 2:
304*c54f35caSApple OSS Distributions            raise ValueError("text is larger than line of text")
305*c54f35caSApple OSS Distributions
306*c54f35caSApple OSS Distributions        lbreak_pos = (len(line) // 2) - (len(text) // 2)
307*c54f35caSApple OSS Distributions        if not even_length:
308*c54f35caSApple OSS Distributions            lbreak_pos -= 1
309*c54f35caSApple OSS Distributions        out = line[:lbreak_pos] + text
310*c54f35caSApple OSS Distributions        return out + line[len(out):]
311*c54f35caSApple OSS Distributions
312*c54f35caSApple OSS Distributions    def get_separator_lines(self):
313*c54f35caSApple OSS Distributions        return ['/' + ' ' * (self.width - 2) + '/', '/' + ' ' * (self.width - 2) + '/']
314*c54f35caSApple OSS Distributions
315*c54f35caSApple OSS Distributions    def printMachoMap(self, mobj):
316*c54f35caSApple OSS Distributions        MapBlock = namedtuple('MapBlock', 'name vmaddr vmsize fileoff filesize extra_info is_segment')
317*c54f35caSApple OSS Distributions        outstr = self.name + '\n'
318*c54f35caSApple OSS Distributions        other_cmds = ''
319*c54f35caSApple OSS Distributions        blocks = []
320*c54f35caSApple OSS Distributions        for hdr in mobj.headers:
321*c54f35caSApple OSS Distributions            cmd_index = 0
322*c54f35caSApple OSS Distributions            for cmd in hdr.commands:
323*c54f35caSApple OSS Distributions                # cmds is [(load_command, segment, [sections..])]
324*c54f35caSApple OSS Distributions                (lc, segment, sections) = cmd
325*c54f35caSApple OSS Distributions                lc_cmd_str = get_load_command_human_name(lc)
326*c54f35caSApple OSS Distributions                lc_str_rep = "\n\t LC: {:s} size:{:d} nsects:{:d}".format(lc_cmd_str, lc.cmdsize, len(sections))
327*c54f35caSApple OSS Distributions                # print lc_str_rep
328*c54f35caSApple OSS Distributions                if isinstance(segment, SEGMENT_TYPES):
329*c54f35caSApple OSS Distributions                    segname = six.ensure_str(segment.segname[:segment.segname.find(b'\x00')])
330*c54f35caSApple OSS Distributions                    # print "\tsegment: {:s} vmaddr: {:x} vmsize:{:d} fileoff: {:x} filesize: {:d}".format(
331*c54f35caSApple OSS Distributions                    #             segname, segment.vmaddr, segment.vmsize, segment.fileoff, segment.filesize)
332*c54f35caSApple OSS Distributions                    blocks.append(MapBlock(segname, segment.vmaddr, segment.vmsize, segment.fileoff, segment.filesize,
333*c54f35caSApple OSS Distributions                                            ' LC:{} : {} init:{:#0X} max:{:#0X}'.format(lc_cmd_str, segname, segment.initprot, segment.maxprot),
334*c54f35caSApple OSS Distributions                                            True))
335*c54f35caSApple OSS Distributions                    for section in sections:
336*c54f35caSApple OSS Distributions                        section_name = six.ensure_str(section.sectname[:section.sectname.find(b'\x00')])
337*c54f35caSApple OSS Distributions                        blocks.append(MapBlock(section_name, section.addr, section.size, section.offset,
338*c54f35caSApple OSS Distributions                                                section.size, 'al:{} flags:{:#0X}'.format(section.align, section.flags), False))
339*c54f35caSApple OSS Distributions                        #print "\t\tsection:{:s} addr:{:x} off:{:x} size:{:d}".format(section_name, section.addr, section.offset, section.size)
340*c54f35caSApple OSS Distributions                elif isinstance(segment, macholib.mach_o.uuid_command):
341*c54f35caSApple OSS Distributions                    other_cmds += "\n\t uuid: {:s}".format(str(uuid.UUID(bytes=segment.uuid)).upper())
342*c54f35caSApple OSS Distributions                elif isinstance(segment, macholib.mach_o.rpath_command):
343*c54f35caSApple OSS Distributions                    other_cmds += "\n\t rpath: {:s}".format(segment.path)
344*c54f35caSApple OSS Distributions                elif isinstance(segment, macholib.mach_o.dylib_command):
345*c54f35caSApple OSS Distributions                    other_cmds += "\n\t dylib: {:s} ({:s})".format(str(sections[:sections.find(b'\x00')]), str(segment.current_version))
346*c54f35caSApple OSS Distributions                else:
347*c54f35caSApple OSS Distributions                    other_cmds += lc_str_rep
348*c54f35caSApple OSS Distributions                cmd_index += 1
349*c54f35caSApple OSS Distributions
350*c54f35caSApple OSS Distributions        # fixup the self.width param
351*c54f35caSApple OSS Distributions        for _b in blocks:
352*c54f35caSApple OSS Distributions            if self.default_side_padding + len(_b.name) + 2 > self.width:
353*c54f35caSApple OSS Distributions                self.width = self.default_side_padding + len(_b.name) + 2
354*c54f35caSApple OSS Distributions        if self.width % 2 != 0:
355*c54f35caSApple OSS Distributions            self.width += 1
356*c54f35caSApple OSS Distributions
357*c54f35caSApple OSS Distributions        sorted_blocks = sorted(blocks, key=lambda b: b.vmaddr)
358*c54f35caSApple OSS Distributions        mstr = [self.get_header_line()]
359*c54f35caSApple OSS Distributions        prev_block = MapBlock('', 0, 0, 0, 0, '', False)
360*c54f35caSApple OSS Distributions        for b in sorted_blocks:
361*c54f35caSApple OSS Distributions            # TODO add separator blocks if vmaddr is large from prev_block
362*c54f35caSApple OSS Distributions            if b.is_segment:
363*c54f35caSApple OSS Distributions                s = self.get_dashed_line()
364*c54f35caSApple OSS Distributions            else:
365*c54f35caSApple OSS Distributions                s = self.get_dotted_line()
366*c54f35caSApple OSS Distributions            s = self.center_text_in_line(s, b.name)
367*c54f35caSApple OSS Distributions            line = "{:s} {: <#020X} ({: <10d}) floff:{: <#08x}  {}".format(s, b.vmaddr, b.vmsize, b.fileoff, b.extra_info)
368*c54f35caSApple OSS Distributions            if (b.vmaddr - prev_block.vmaddr) > VisualMachoMap.KB_16:
369*c54f35caSApple OSS Distributions                mstr.append(self.get_space_line())
370*c54f35caSApple OSS Distributions                mstr.append(self.get_space_line())
371*c54f35caSApple OSS Distributions
372*c54f35caSApple OSS Distributions            mstr.append(line)
373*c54f35caSApple OSS Distributions
374*c54f35caSApple OSS Distributions            if b.vmsize > VisualMachoMap.MB_1:
375*c54f35caSApple OSS Distributions                mstr.append(self.get_space_line())
376*c54f35caSApple OSS Distributions                mstr.extend(self.get_separator_lines())
377*c54f35caSApple OSS Distributions                mstr.append(self.get_space_line())
378*c54f35caSApple OSS Distributions            #mstr.append(self.get_space_line())
379*c54f35caSApple OSS Distributions            prev_block = b
380*c54f35caSApple OSS Distributions        mstr.append(self.get_space_line())
381*c54f35caSApple OSS Distributions        if prev_block.vmsize > VisualMachoMap.KB_16:
382*c54f35caSApple OSS Distributions            mstr.append(self.get_space_line())
383*c54f35caSApple OSS Distributions        mstr.append(self.get_header_line())
384*c54f35caSApple OSS Distributions        print(outstr)
385*c54f35caSApple OSS Distributions        print("\n".join(mstr))
386*c54f35caSApple OSS Distributions        print("\n\n=============== Other Load Commands ===============")
387*c54f35caSApple OSS Distributions        print(other_cmds)
388*c54f35caSApple OSS Distributions
389*c54f35caSApple OSS Distributions
390*c54f35caSApple OSS Distributionsif __name__ == '__main__':
391*c54f35caSApple OSS Distributions    import sys
392*c54f35caSApple OSS Distributions    if len(sys.argv) < 2:
393*c54f35caSApple OSS Distributions        print("Usage: {} /path/to/macho_binary".format(sys.argv[0]))
394*c54f35caSApple OSS Distributions        sys.exit(1)
395*c54f35caSApple OSS Distributions    with open(sys.argv[-1], 'rb') as fp:
396*c54f35caSApple OSS Distributions        mobject = MemMachO(fp)
397*c54f35caSApple OSS Distributions
398*c54f35caSApple OSS Distributions        p = VisualMachoMap(sys.argv[-1])
399*c54f35caSApple OSS Distributions        p.printMachoMap(mobject)
400*c54f35caSApple OSS Distributions    sys.exit(0)
401