chromium/tools/mac/dump-static-initializers.py

#!/usr/bin/env python
# Copyright 2013 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Dumps a list of files with static initializers. Use with release builds.

Usage:
  tools/mac/dump-static-initializers.py out/Release/Chromium\ Framework.framework.dSYM/Contents/Resources/DWARF/Chromium\ Framework

Do NOT use mac_strip_release=0 or component=shared_library if you want to use
this script.

This is meant to be used on a dSYM file. If only an unstripped executable is
present, use show_mod_init_func.py.
"""

from __future__ import print_function

import optparse
import re
import subprocess
import sys

# Matches for example:
# [     1] 000001ca 64 (N_SO         ) 00     0000   0000000000000000 'test.cc'
dsymutil_file_re = re.compile("N_SO.*'([^']*)'")

# Matches for example:
# [     2] 000001d2 66 (N_OSO        ) 00     0001   000000004ed856a0 '/Volumes/MacintoshHD2/src/chrome-git/src/test.o'
dsymutil_o_file_re = re.compile("N_OSO.*'([^']*)'")

# Matches for example:
# [     8] 00000233 24 (N_FUN        ) 01     0000   0000000000001b40 '__GLOBAL__I_s'
# [185989] 00dc69ef 26 (N_STSYM      ) 02     0000   00000000022e2290 '__GLOBAL__I_a'
dsymutil_re = re.compile(r"(?:N_FUN|N_STSYM).*\s[0-9a-f]*\s'__GLOBAL__I_")

def ParseDsymutil(binary):
  """Given a binary, prints source and object filenames for files with
  static initializers.
  """

  child = subprocess.Popen(['tools/clang/dsymutil/bin/dsymutil', '-s', binary],
     stdout=subprocess.PIPE)
  for line in child.stdout:
    file_match = dsymutil_file_re.search(line)
    if file_match:
      current_filename = file_match.group(1)
    else:
      o_file_match = dsymutil_o_file_re.search(line)
      if o_file_match:
        current_o_filename = o_file_match.group(1)
      else:
        match = dsymutil_re.search(line)
        if match:
          print(current_filename)
          print(current_o_filename)
          print()


def main():
  parser = optparse.OptionParser(usage='%prog filename')
  opts, args = parser.parse_args()
  if len(args) != 1:
    parser.error('missing filename argument')
    return 1
  binary = args[0]

  ParseDsymutil(binary)
  return 0


if '__main__' == __name__:
  sys.exit(main())