1#!/usr/bin/env python
2# Copyright (c) 2013 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""
7Dumps a list of files with static initializers. Use with release builds.
8
9Usage:
10  tools/mac/dump-static-initializers.py out/Release/Chromium\ Framework.framework.dSYM/Contents/Resources/DWARF/Chromium\ Framework
11
12Do NOT use mac_strip_release=0 or component=shared_library if you want to use
13this script.
14"""
15
16import optparse
17import re
18import subprocess
19import sys
20
21# Matches for example:
22# [     1] 000001ca 64 (N_SO         ) 00     0000   0000000000000000 'test.cc'
23dsymutil_file_re = re.compile("N_SO.*'([^']*)'")
24
25# Matches for example:
26# [     2] 000001d2 66 (N_OSO        ) 00     0001   000000004ed856a0 '/Volumes/MacintoshHD2/src/chrome-git/src/test.o'
27dsymutil_o_file_re = re.compile("N_OSO.*'([^']*)'")
28
29# Matches for example:
30# [     8] 00000233 24 (N_FUN        ) 01     0000   0000000000001b40 '__GLOBAL__I_s'
31# [185989] 00dc69ef 26 (N_STSYM      ) 02     0000   00000000022e2290 '__GLOBAL__I_a'
32dsymutil_re = re.compile(r"(?:N_FUN|N_STSYM).*\s[0-9a-f]*\s'__GLOBAL__I_")
33
34def ParseDsymutil(binary):
35  """Given a binary, prints source and object filenames for files with
36  static initializers.
37  """
38
39  child = subprocess.Popen(['dsymutil', '-s', binary], stdout=subprocess.PIPE)
40  for line in child.stdout:
41    file_match = dsymutil_file_re.search(line)
42    if file_match:
43      current_filename = file_match.group(1)
44    else:
45      o_file_match = dsymutil_o_file_re.search(line)
46      if o_file_match:
47        current_o_filename = o_file_match.group(1)
48      else:
49        match = dsymutil_re.search(line)
50        if match:
51          print current_filename
52          print current_o_filename
53          print
54
55
56def main():
57  parser = optparse.OptionParser(usage='%prog filename')
58  opts, args = parser.parse_args()
59  if len(args) != 1:
60    parser.error('missing filename argument')
61    return 1
62  binary = args[0]
63
64  ParseDsymutil(binary)
65  return 0
66
67
68if '__main__' == __name__:
69  sys.exit(main())
70