Home | History | Annotate | Download | only in binary_size
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Common utilities for tools that deal with binary size information.
      6 """
      7 
      8 import logging
      9 import re
     10 
     11 
     12 def ParseNm(nm_lines):
     13   """Parse nm output, returning data for all relevant (to binary size)
     14   symbols and ignoring the rest.
     15 
     16   Args:
     17       nm_lines: an iterable over lines of nm output.
     18 
     19   Yields:
     20       (symbol name, symbol type, symbol size, source file path).
     21 
     22       Path may be None if nm couldn't figure out the source file.
     23   """
     24 
     25   # Match lines with size, symbol, optional location, optional discriminator
     26   sym_re = re.compile(r'^[0-9a-f]{8,} ' # address (8+ hex digits)
     27                       '([0-9a-f]{8,}) ' # size (8+ hex digits)
     28                       '(.) ' # symbol type, one character
     29                       '([^\t]+)' # symbol name, separated from next by tab
     30                       '(?:\t(.*):[\d\?]+)?.*$') # location
     31   # Match lines with addr but no size.
     32   addr_re = re.compile(r'^[0-9a-f]{8,} (.) ([^\t]+)(?:\t.*)?$')
     33   # Match lines that don't have an address at all -- typically external symbols.
     34   noaddr_re = re.compile(r'^ {8,} (.) (.*)$')
     35   # Match lines with no symbol name, only addr and type
     36   addr_only_re = re.compile(r'^[0-9a-f]{8,} (.)$')
     37 
     38   for line in nm_lines:
     39     line = line.rstrip()
     40     match = sym_re.match(line)
     41     if match:
     42       size, sym_type, sym = match.groups()[0:3]
     43       size = int(size, 16)
     44       if sym_type in ('B', 'b'):
     45         continue  # skip all BSS for now.
     46       path = match.group(4)
     47       yield sym, sym_type, size, path
     48       continue
     49     match = addr_re.match(line)
     50     if match:
     51       # sym_type, sym = match.groups()[0:2]
     52       continue  # No size == we don't care.
     53     match = noaddr_re.match(line)
     54     if match:
     55       sym_type, sym = match.groups()
     56       if sym_type in ('U', 'w'):
     57         continue  # external or weak symbol
     58     match = addr_only_re.match(line)
     59     if match:
     60       continue  # Nothing to do.
     61 
     62 
     63     # If we reach this part of the loop, there was something in the
     64     # line that we didn't expect or recognize.
     65     logging.warning('nm output parser failed to parse: %s', repr(line))
     66