PageRenderTime 127ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/generate_breakpad_symbols.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 136 lines | 82 code | 21 blank | 33 comment | 16 complexity | 6943890204bbc1e1bf1782bebb267d02 MD5 | raw file
Possible License(s): LGPL-2.1
  1. #!/usr/bin/env python
  2. """\
  3. @file generate_breakpad_symbols.py
  4. @author Brad Kittenbrink <brad@lindenlab.com>
  5. @brief Simple tool for generating google_breakpad symbol information
  6. for the crash reporter.
  7. $LicenseInfo:firstyear=2010&license=viewerlgpl$
  8. Second Life Viewer Source Code
  9. Copyright (C) 2010-2011, Linden Research, Inc.
  10. This library is free software; you can redistribute it and/or
  11. modify it under the terms of the GNU Lesser General Public
  12. License as published by the Free Software Foundation;
  13. version 2.1 of the License only.
  14. This library is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. Lesser General Public License for more details.
  18. You should have received a copy of the GNU Lesser General Public
  19. License along with this library; if not, write to the Free Software
  20. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  22. $/LicenseInfo$
  23. """
  24. import collections
  25. import fnmatch
  26. import itertools
  27. import operator
  28. import os
  29. import re
  30. import sys
  31. import shlex
  32. import subprocess
  33. import tarfile
  34. import StringIO
  35. def usage():
  36. print >>sys.stderr, "usage: %s viewer_dir viewer_exes libs_suffix dump_syms_tool viewer_symbol_file" % sys.argv[0]
  37. class MissingModuleError(Exception):
  38. def __init__(self, modules):
  39. Exception.__init__(self, "Failed to find required modules: %r" % modules)
  40. self.modules = modules
  41. def main(configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file):
  42. print "generate_breakpad_symbols run with args: %s" % str((configuration, viewer_dir, viewer_exes, libs_suffix, dump_syms_tool, viewer_symbol_file))
  43. if not re.match("release", configuration, re.IGNORECASE):
  44. print "skipping breakpad symbol generation for non-release build."
  45. return 0
  46. # split up list of viewer_exes
  47. # "'Second Life' SLPlugin" becomes ['Second Life', 'SLPlugin']
  48. viewer_exes = shlex.split(viewer_exes)
  49. found_required = dict([(module, False) for module in viewer_exes])
  50. def matches(f):
  51. if f in viewer_exes:
  52. found_required[f] = True
  53. return True
  54. return fnmatch.fnmatch(f, libs_suffix)
  55. def list_files():
  56. for (dirname, subdirs, filenames) in os.walk(viewer_dir):
  57. #print "scanning '%s' for modules..." % dirname
  58. for f in itertools.ifilter(matches, filenames):
  59. yield os.path.join(dirname, f)
  60. def dump_module(m):
  61. print "dumping module '%s' with '%s'..." % (m, dump_syms_tool)
  62. child = subprocess.Popen([dump_syms_tool, m] , stdout=subprocess.PIPE)
  63. out, err = child.communicate()
  64. return (m,child.returncode, out, err)
  65. out = tarfile.open(viewer_symbol_file, 'w:bz2')
  66. for (filename,status,symbols,err) in itertools.imap(dump_module, list_files()):
  67. if status == 0:
  68. module_line = symbols[:symbols.index('\n')]
  69. module_line = module_line.split()
  70. hash_id = module_line[3]
  71. module = ' '.join(module_line[4:])
  72. if sys.platform in ['win32', 'cygwin']:
  73. mod_name = module[:module.rindex('.pdb')]
  74. else:
  75. mod_name = module
  76. symbolfile = StringIO.StringIO(symbols)
  77. info = tarfile.TarInfo("%(module)s/%(hash_id)s/%(mod_name)s.sym" % dict(module=module, hash_id=hash_id, mod_name=mod_name))
  78. info.size = symbolfile.len
  79. out.addfile(info, symbolfile)
  80. else:
  81. print >>sys.stderr, "warning: failed to dump symbols for '%s': %s" % (filename, err)
  82. out.close()
  83. missing_modules = [m for (m,_) in
  84. itertools.ifilter(lambda (k,v): not v, found_required.iteritems())
  85. ]
  86. if missing_modules:
  87. print >> sys.stderr, "failed to generate %s" % viewer_symbol_file
  88. os.remove(viewer_symbol_file)
  89. raise MissingModuleError(missing_modules)
  90. symbols = tarfile.open(viewer_symbol_file, 'r:bz2')
  91. tarfile_members = symbols.getnames()
  92. symbols.close()
  93. for required_module in viewer_exes:
  94. def match_module_basename(m):
  95. return os.path.splitext(required_module)[0].lower() \
  96. == os.path.splitext(os.path.basename(m))[0].lower()
  97. # there must be at least one .sym file in tarfile_members that matches
  98. # each required module (ignoring file extensions)
  99. if not reduce(operator.or_, itertools.imap(match_module_basename, tarfile_members)):
  100. print >> sys.stderr, "failed to find required %s in generated %s" \
  101. % (required_module, viewer_symbol_file)
  102. os.remove(viewer_symbol_file)
  103. raise MissingModuleError([required_module])
  104. print "successfully generated %s including required modules '%s'" % (viewer_symbol_file, viewer_exes)
  105. return 0
  106. if __name__ == "__main__":
  107. if len(sys.argv) != 7:
  108. usage()
  109. sys.exit(1)
  110. sys.exit(main(*sys.argv[1:]))