OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 | 2 |
3 # Copyright (c) 2008 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2008 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # Usage: strip_save_dsym <whatever-arguments-you-would-pass-to-strip> | 7 # Usage: strip_save_dsym <whatever-arguments-you-would-pass-to-strip> |
8 # | 8 # |
9 # strip_save_dsym is a wrapper around the standard strip utility. Given an | 9 # strip_save_dsym is a wrapper around the standard strip utility. Given an |
10 # input Mach-O file, strip_save_dsym will save a copy of the file in a "fake" | 10 # input Mach-O file, strip_save_dsym will save a copy of the file in a "fake" |
(...skipping 25 matching lines...) Expand all Loading... |
36 import sys | 36 import sys |
37 import time | 37 import time |
38 | 38 |
39 # Returns a list of architectures contained in a Mach-O file. The file can be | 39 # Returns a list of architectures contained in a Mach-O file. The file can be |
40 # a universal (fat) file, in which case there will be one list element for | 40 # a universal (fat) file, in which case there will be one list element for |
41 # each contained architecture, or it can be a thin single-architecture Mach-O | 41 # each contained architecture, or it can be a thin single-architecture Mach-O |
42 # file, in which case the list will contain a single element identifying the | 42 # file, in which case the list will contain a single element identifying the |
43 # architecture. On error, returns an empty list. Determines the architecture | 43 # architecture. On error, returns an empty list. Determines the architecture |
44 # list by calling file. | 44 # list by calling file. |
45 def macho_archs(macho): | 45 def macho_archs(macho): |
| 46 macho_types = ["executable", |
| 47 "dynamically linked shared library", |
| 48 "bundle"] |
| 49 macho_types_re = "Mach-O (?:64-bit )?(?:" + "|".join(macho_types) + ")" |
| 50 |
46 file_cmd = subprocess.Popen(["/usr/bin/file", "-b", "--", macho], | 51 file_cmd = subprocess.Popen(["/usr/bin/file", "-b", "--", macho], |
47 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 52 stdout=subprocess.PIPE) |
48 | 53 |
49 archs = [] | 54 archs = [] |
50 | 55 |
51 type_line = file_cmd.stdout.readline() | 56 type_line = file_cmd.stdout.readline() |
52 type_match = re.match("^Mach-O executable (.*)$", type_line) | 57 type_match = re.match("^%s (.*)$" % macho_types_re, type_line) |
53 if type_match: | 58 if type_match: |
54 archs.append(type_match.group(1)) | 59 archs.append(type_match.group(1)) |
55 return [type_match.group(1)] | 60 return [type_match.group(1)] |
56 else: | 61 else: |
57 type_match = re.match("^Mach-O universal binary with (.*) architectures$", | 62 type_match = re.match("^Mach-O universal binary with (.*) architectures$", |
58 type_line) | 63 type_line) |
59 if type_match: | 64 if type_match: |
60 for i in range(0, int(type_match.group(1))): | 65 for i in range(0, int(type_match.group(1))): |
61 arch_line = file_cmd.stdout.readline() | 66 arch_line = file_cmd.stdout.readline() |
62 arch_match = re.match( | 67 arch_match = re.match( |
63 "^.* \(for architecture (.*)\):\tMach-O executable .*$", | 68 "^.* \(for architecture (.*)\):\t%s .*$" % macho_types_re, |
64 arch_line) | 69 arch_line) |
65 if arch_match: | 70 if arch_match: |
66 archs.append(arch_match.group(1)) | 71 archs.append(arch_match.group(1)) |
67 | 72 |
68 if file_cmd.wait() != 0: | 73 if file_cmd.wait() != 0: |
69 archs = [] | 74 archs = [] |
70 | 75 |
| 76 if len(archs) == 0: |
| 77 print >> sys.stderr, "No architectures in %s" % macho |
| 78 |
71 return archs | 79 return archs |
72 | 80 |
73 # Returns a dictionary mapping architectures contained in the file as returned | 81 # Returns a dictionary mapping architectures contained in the file as returned |
74 # by macho_archs to the LC_UUID load command for that architecture. | 82 # by macho_archs to the LC_UUID load command for that architecture. |
75 # Architectures with no LC_UUID load command are omitted from the dictionary. | 83 # Architectures with no LC_UUID load command are omitted from the dictionary. |
76 # Determines the UUID value by calling otool. | 84 # Determines the UUID value by calling otool. |
77 def macho_uuids(macho): | 85 def macho_uuids(macho): |
| 86 uuids = {} |
| 87 |
78 archs = macho_archs(macho) | 88 archs = macho_archs(macho) |
79 | 89 if len(archs) == 0: |
80 uuids = {} | 90 return uuids |
81 | 91 |
82 for arch in archs: | 92 for arch in archs: |
83 if arch == "": | 93 if arch == "": |
84 continue | 94 continue |
85 | 95 |
86 otool_cmd = subprocess.Popen(["/usr/bin/otool", "-arch", arch, "-l", "-", | 96 otool_cmd = subprocess.Popen(["/usr/bin/otool", "-arch", arch, "-l", "-", |
87 macho], | 97 macho], |
88 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 98 stdout=subprocess.PIPE) |
89 # state 0 is when nothing UUID-related has been seen yet. State 1 is | 99 # state 0 is when nothing UUID-related has been seen yet. State 1 is |
90 # entered after a load command begins, but it may not be an LC_UUID load | 100 # entered after a load command begins, but it may not be an LC_UUID load |
91 # command. States 2, 3, and 4 are intermediate states while reading an | 101 # command. States 2, 3, and 4 are intermediate states while reading an |
92 # LC_UUID command. State 5 is the terminal state for a successful LC_UUID | 102 # LC_UUID command. State 5 is the terminal state for a successful LC_UUID |
93 # read. State 6 is the error state. | 103 # read. State 6 is the error state. |
94 state = 0 | 104 state = 0 |
95 uuid = "" | 105 uuid = "" |
96 for otool_line in otool_cmd.stdout: | 106 for otool_line in otool_cmd.stdout: |
97 if state == 0: | 107 if state == 0: |
98 if re.match("^Load command .*$", otool_line): | 108 if re.match("^Load command .*$", otool_line): |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 uuid_match.group(7) + uuid_match.group(8) | 141 uuid_match.group(7) + uuid_match.group(8) |
132 else: | 142 else: |
133 state = 6 | 143 state = 6 |
134 | 144 |
135 if otool_cmd.wait() != 0: | 145 if otool_cmd.wait() != 0: |
136 state = 6 | 146 state = 6 |
137 | 147 |
138 if state == 5: | 148 if state == 5: |
139 uuids[arch] = uuid.upper() | 149 uuids[arch] = uuid.upper() |
140 | 150 |
| 151 if len(uuids) == 0: |
| 152 print >> sys.stderr, "No UUIDs in %s" % macho |
| 153 |
141 return uuids | 154 return uuids |
142 | 155 |
143 # Given a path to a Mach-O file and possible information from the environment, | 156 # Given a path to a Mach-O file and possible information from the environment, |
144 # determines the desired path to the .dSYM. | 157 # determines the desired path to the .dSYM. |
145 def dsym_path(macho): | 158 def dsym_path(macho): |
146 # If building a bundle, the .dSYM should be placed next to the bundle. Use | 159 # If building a bundle, the .dSYM should be placed next to the bundle. Use |
147 # WRAPPER_NAME to make this determination. If called from xcodebuild, | 160 # WRAPPER_NAME to make this determination. If called from xcodebuild, |
148 # WRAPPER_NAME will be set to the name of the bundle. | 161 # WRAPPER_NAME will be set to the name of the bundle. |
149 dsym = "" | 162 dsym = "" |
150 if "WRAPPER_NAME" in os.environ: | 163 if "WRAPPER_NAME" in os.environ: |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 | 315 |
303 if macho is None: | 316 if macho is None: |
304 print >> sys.stderr, "Nothing to strip" | 317 print >> sys.stderr, "Nothing to strip" |
305 return 1 | 318 return 1 |
306 | 319 |
307 if not strip_and_make_fake_dsym(macho): | 320 if not strip_and_make_fake_dsym(macho): |
308 return 1 | 321 return 1 |
309 | 322 |
310 return 0 | 323 return 0 |
311 | 324 |
312 if __name__ == '__main__': | 325 if __name__ == "__main__": |
313 sys.exit(main(sys.argv)) | 326 sys.exit(main(sys.argv)) |
OLD | NEW |