shlib-compat.py revision 291036
1248693Sgleb#!/usr/bin/env python 2248693Sgleb#- 3248693Sgleb# Copyright (c) 2010 Gleb Kurtsou 4248693Sgleb# All rights reserved. 5248693Sgleb# 6248693Sgleb# Redistribution and use in source and binary forms, with or without 7248693Sgleb# modification, are permitted provided that the following conditions 8248693Sgleb# are met: 9248693Sgleb# 1. Redistributions of source code must retain the above copyright 10248693Sgleb# notice, this list of conditions and the following disclaimer. 11248693Sgleb# 2. Redistributions in binary form must reproduce the above copyright 12248693Sgleb# notice, this list of conditions and the following disclaimer in the 13248693Sgleb# documentation and/or other materials provided with the distribution. 14248693Sgleb# 15248693Sgleb# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16248693Sgleb# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17248693Sgleb# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18248693Sgleb# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19248693Sgleb# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20248693Sgleb# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21248693Sgleb# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22248693Sgleb# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23248693Sgleb# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24248693Sgleb# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25248693Sgleb# SUCH DAMAGE. 26248693Sgleb# 27248693Sgleb# $FreeBSD: head/tools/tools/shlib-compat/shlib-compat.py 291036 2015-11-18 23:32:29Z rodrigc $ 28248693Sgleb 29248693Sglebimport os 30248693Sglebimport sys 31248693Sglebimport re 32248693Sglebimport optparse 33248693Sgleb 34248693Sglebclass Config(object): 35248693Sgleb version = '0.1' 36248693Sgleb # controlled by user 37248693Sgleb verbose = 0 38248693Sgleb dump = False 39248693Sgleb no_dump = False 40248693Sgleb version_filter = None 41248693Sgleb symbol_filter = None 42248693Sgleb alias_prefixes = [] 43248693Sgleb # misc opts 44248693Sgleb objdump = 'objdump' 45248693Sgleb dwarfdump = 'dwarfdump' 46248693Sgleb # debug 47248693Sgleb cmpcache_enabled = True 48248693Sgleb dwarfcache_enabled = True 49248693Sgleb w_alias = True 50248693Sgleb w_cached = False 51248693Sgleb w_symbol = True 52248693Sgleb 53248693Sgleb class FileConfig(object): 54248693Sgleb filename = None 55248693Sgleb out = sys.stdout 56248693Sgleb def init(self, outname): 57248693Sgleb if outname and outname != '-': 58248693Sgleb self.out = open(outname, "w") 59248693Sgleb 60248693Sgleb origfile = FileConfig() 61248693Sgleb newfile = FileConfig() 62248693Sgleb 63275354Sgleb exclude_sym_default = [ 64275354Sgleb '^__bss_start$', 65275354Sgleb '^_edata$', 66275354Sgleb '^_end$', 67275354Sgleb '^_fini$', 68275354Sgleb '^_init$', 69275354Sgleb ] 70275354Sgleb 71248693Sgleb @classmethod 72248693Sgleb def init(cls): 73248693Sgleb cls.version_filter = StrFilter() 74248693Sgleb cls.symbol_filter = StrFilter() 75248693Sgleb 76248693Sglebclass App(object): 77248693Sgleb result_code = 0 78248693Sgleb 79248693Sglebdef warn(cond, msg): 80248693Sgleb if cond: 81248693Sgleb print >> sys.stderr, "WARN: " + msg 82248693Sgleb 83248693Sgleb# {{{ misc 84248693Sgleb 85248693Sglebclass StrFilter(object): 86248693Sgleb def __init__(self): 87248693Sgleb self.exclude = [] 88248693Sgleb self.include = [] 89248693Sgleb 90248693Sgleb def compile(self): 91248693Sgleb self.re_exclude = [ re.compile(x) for x in self.exclude ] 92248693Sgleb self.re_include = [ re.compile(x) for x in self.include ] 93248693Sgleb 94248693Sgleb def match(self, s): 95248693Sgleb if len(self.re_include): 96248693Sgleb matched = False 97248693Sgleb for r in self.re_include: 98248693Sgleb if r.match(s): 99248693Sgleb matched = True 100248693Sgleb break 101248693Sgleb if not matched: 102248693Sgleb return False 103248693Sgleb for r in self.re_exclude: 104248693Sgleb if r.match(s): 105248693Sgleb return False 106248693Sgleb return True 107248693Sgleb 108248693Sglebclass Cache(object): 109248693Sgleb 110248693Sgleb class CacheStats(object): 111248693Sgleb def __init__(self): 112248693Sgleb self.hit = 0 113248693Sgleb self.miss = 0 114248693Sgleb 115248693Sgleb def show(self, name): 116248693Sgleb total = self.hit + self.miss 117248693Sgleb if total == 0: 118248693Sgleb ratio = '(undef)' 119248693Sgleb else: 120248693Sgleb ratio = '%f' % (self.hit/float(total)) 121248693Sgleb return '%s cache stats: hit: %d; miss: %d; ratio: %s' % \ 122248693Sgleb (name, self.hit, self.miss, ratio) 123248693Sgleb 124248693Sgleb def __init__(self, enabled=True, stats=None): 125248693Sgleb self.enabled = enabled 126248693Sgleb self.items = {} 127248693Sgleb if stats == None: 128248693Sgleb self.stats = Cache.CacheStats() 129248693Sgleb else: 130248693Sgleb self.stats = stats 131248693Sgleb 132248693Sgleb def get(self, id): 133291036Srodrigc if self.enabled and id in self.items: 134248693Sgleb self.stats.hit += 1 135248693Sgleb return self.items[id] 136248693Sgleb else: 137248693Sgleb self.stats.miss += 1 138248693Sgleb return None 139248693Sgleb 140248693Sgleb def put(self, id, obj): 141248693Sgleb if self.enabled: 142291036Srodrigc if id in self.items and obj is not self.items[id]: 143248693Sgleb #raise ValueError("Item is already cached: %d (%s, %s)" % 144248693Sgleb # (id, self.items[id], obj)) 145248693Sgleb warn(Config.w_cached, "Item is already cached: %d (%s, %s)" % \ 146248693Sgleb (id, self.items[id], obj)) 147248693Sgleb self.items[id] = obj 148248693Sgleb 149248693Sgleb def replace(self, id, obj): 150248693Sgleb if self.enabled: 151291036Srodrigc assert id in self.items 152248693Sgleb self.items[id] = obj 153248693Sgleb 154248693Sglebclass ListDiff(object): 155248693Sgleb def __init__(self, orig, new): 156248693Sgleb self.orig = set(orig) 157248693Sgleb self.new = set(new) 158248693Sgleb self.common = self.orig & self.new 159248693Sgleb self.added = self.new - self.common 160248693Sgleb self.removed = self.orig - self.common 161248693Sgleb 162248693Sglebclass PrettyPrinter(object): 163248693Sgleb def __init__(self): 164248693Sgleb self.stack = [] 165248693Sgleb 166248693Sgleb def run_nested(self, obj): 167248693Sgleb ex = obj._pp_ex(self) 168248693Sgleb self.stack.append(ex) 169248693Sgleb 170248693Sgleb def run(self, obj): 171248693Sgleb self._result = obj._pp(self) 172248693Sgleb return self._result 173248693Sgleb 174248693Sgleb def nested(self): 175248693Sgleb return sorted(set(self.stack)) 176248693Sgleb 177248693Sgleb def result(self): 178248693Sgleb return self._result; 179248693Sgleb 180248693Sgleb# }}} 181248693Sgleb 182248693Sgleb#{{{ symbols and version maps 183248693Sgleb 184248693Sglebclass Symbol(object): 185248693Sgleb def __init__(self, name, offset, version, lib): 186248693Sgleb self.name = name 187248693Sgleb self.offset = offset 188248693Sgleb self.version = version 189248693Sgleb self.lib = lib 190248693Sgleb self.definition = None 191248693Sgleb 192248693Sgleb @property 193248693Sgleb def name_ver(self): 194248693Sgleb return self.name + '@' + self.version 195248693Sgleb 196248693Sgleb def __repr__(self): 197248693Sgleb return "Symbol(%s, 0x%x, %s)" % (self.name, self.offset, self.version) 198248693Sgleb 199248693Sglebclass CommonSymbol(object): 200248693Sgleb def __init__(self, origsym, newsym): 201248693Sgleb if origsym.name != newsym.name or origsym.version != newsym.version: 202248693Sgleb raise RuntimeError("Symbols have different names: %s", 203248693Sgleb [origsym, newsym]) 204248693Sgleb self.origsym = origsym 205248693Sgleb self.newsym = newsym 206248693Sgleb self.name = newsym.name 207248693Sgleb self.version = newsym.version 208248693Sgleb 209248693Sgleb def __repr__(self): 210248693Sgleb return "CommonSymbol(%s, %s)" % (self.name, self.version) 211248693Sgleb 212248693Sglebclass SymbolAlias(object): 213248693Sgleb def __init__(self, alias, prefix, offset): 214248693Sgleb assert alias.startswith(prefix) 215248693Sgleb self.alias = alias 216248693Sgleb self.name = alias[len(prefix):] 217248693Sgleb self.offset = offset 218248693Sgleb 219248693Sgleb def __repr__(self): 220248693Sgleb return "SymbolAlias(%s, 0x%x)" % (self.alias, self.offset) 221248693Sgleb 222248693Sgleb 223248693Sglebclass VersionMap(object): 224248693Sgleb def __init__(self, name): 225248693Sgleb self.name = name 226248693Sgleb self.symbols = {} 227248693Sgleb 228248693Sgleb def append(self, symbol): 229291036Srodrigc if (symbol.name in self.symbols): 230248693Sgleb raise ValueError("Symbol is already defined %s@%s" % 231248693Sgleb (symbol.name, self.name)) 232248693Sgleb self.symbols[symbol.name] = symbol 233248693Sgleb 234248693Sgleb def names(self): 235248693Sgleb return self.symbols.keys() 236248693Sgleb 237248693Sgleb def __repr__(self): 238248693Sgleb return repr(self.symbols.values()) 239248693Sgleb 240248693Sgleb# }}} 241248693Sgleb 242248693Sgleb# {{{ types and definitions 243248693Sgleb 244248693Sglebclass Def(object): 245248693Sgleb _is_alias = False 246248693Sgleb 247248693Sgleb def __init__(self, id, name, **kwargs): 248248693Sgleb self.id = id 249248693Sgleb self.name = name 250248693Sgleb self.attrs = kwargs 251248693Sgleb 252248693Sgleb def __getattr__(self, attr): 253291036Srodrigc if attr not in self.attrs: 254248693Sgleb raise AttributeError('%s in %s' % (attr, str(self))) 255248693Sgleb return self.attrs[attr] 256248693Sgleb 257248693Sgleb def _name_opt(self, default=''): 258248693Sgleb if not self.name: 259248693Sgleb return default 260248693Sgleb return self.name 261248693Sgleb 262248693Sgleb def _alias(self): 263248693Sgleb if self._is_alias: 264248693Sgleb return self.type._alias() 265248693Sgleb return self 266248693Sgleb 267248693Sgleb def __cmp__(self, other): 268248693Sgleb # TODO assert 'self' and 'other' belong to different libraries 269248693Sgleb #print 'cmp defs: %s, %s' % (self, other) 270248693Sgleb a = self._alias() 271248693Sgleb try: 272248693Sgleb b = other._alias() 273248693Sgleb except AttributeError: 274248693Sgleb return 1 275248693Sgleb r = cmp(a.__class__, b.__class__) 276248693Sgleb if r == 0: 277248693Sgleb if a.id != 0 and b.id != 0: 278248693Sgleb ind = (long(a.id) << 32) + b.id 279248693Sgleb r = Dwarf.cmpcache.get(ind) 280248693Sgleb if r != None: 281248693Sgleb return r 282248693Sgleb else: 283248693Sgleb ind = 0 284248693Sgleb r = cmp(a.attrs, b.attrs) 285248693Sgleb if ind != 0: 286248693Sgleb Dwarf.cmpcache.put(ind, r) 287248693Sgleb else: 288248693Sgleb r = 0 289248693Sgleb #raise RuntimeError('Comparing different classes: %s, %s' % 290248693Sgleb # (a.__class__.__name__, b.__class__.__name__)) 291248693Sgleb return r 292248693Sgleb 293248693Sgleb def __repr__(self): 294248693Sgleb p = [] 295248693Sgleb if hasattr(self, 'name'): 296248693Sgleb p.append("name=%s" % self.name) 297248693Sgleb for (k, v) in self.attrs.items(): 298248693Sgleb if isinstance(v, Def): 299248693Sgleb v = v.__class__.__name__ + '(...)' 300248693Sgleb p.append("%s=%s" % (k, v)) 301248693Sgleb return self.__class__.__name__ + '(' + ', '.join(p) + ')' 302248693Sgleb 303248693Sgleb def _mapval(self, param, vals): 304248693Sgleb if param not in vals.keys(): 305248693Sgleb raise NotImplementedError("Invalid value '%s': %s" % 306248693Sgleb (param, str(self))) 307248693Sgleb return vals[param] 308248693Sgleb 309248693Sgleb def _pp_ex(self, pp): 310248693Sgleb raise NotImplementedError('Extended pretty print not implemeted: %s' % 311248693Sgleb str(self)) 312248693Sgleb 313248693Sgleb def _pp(self, pp): 314248693Sgleb raise NotImplementedError('Pretty print not implemeted: %s' % str(self)) 315248693Sgleb 316248693Sglebclass AnonymousDef(Def): 317248693Sgleb def __init__(self, id, **kwargs): 318248693Sgleb Def.__init__(self, id, None, **kwargs) 319248693Sgleb 320248693Sglebclass Void(AnonymousDef): 321248693Sgleb _instance = None 322248693Sgleb 323248693Sgleb def __new__(cls, *args, **kwargs): 324248693Sgleb if not cls._instance: 325248693Sgleb cls._instance = super(Void, cls).__new__( 326248693Sgleb cls, *args, **kwargs) 327248693Sgleb return cls._instance 328248693Sgleb 329248693Sgleb def __init__(self): 330248693Sgleb AnonymousDef.__init__(self, 0) 331248693Sgleb 332248693Sgleb def _pp(self, pp): 333248693Sgleb return "void" 334248693Sgleb 335248693Sglebclass VarArgs(AnonymousDef): 336248693Sgleb def _pp(self, pp): 337248693Sgleb return "..." 338248693Sgleb 339248693Sglebclass PointerDef(AnonymousDef): 340248693Sgleb def _pp(self, pp): 341248693Sgleb t = pp.run(self.type) 342248693Sgleb return "%s*" % (t,) 343248693Sgleb 344248693Sglebclass BaseTypeDef(Def): 345248693Sgleb inttypes = ['DW_ATE_signed', 'DW_ATE_unsigned', 'DW_ATE_unsigned_char'] 346248693Sgleb def _pp(self, pp): 347248693Sgleb if self.encoding in self.inttypes: 348248693Sgleb sign = '' if self.encoding == 'DW_ATE_signed' else 'u' 349275354Sgleb bits = int(self.byte_size, 0) * 8 350248693Sgleb return '%sint%s_t' % (sign, bits) 351275354Sgleb elif self.encoding == 'DW_ATE_signed_char' and int(self.byte_size, 0) == 1: 352248693Sgleb return 'char'; 353275354Sgleb elif self.encoding == 'DW_ATE_boolean' and int(self.byte_size, 0) == 1: 354275354Sgleb return 'bool'; 355248693Sgleb elif self.encoding == 'DW_ATE_float': 356275354Sgleb return self._mapval(int(self.byte_size, 0), { 357275354Sgleb 16: 'long double', 358275354Sgleb 8: 'double', 359275354Sgleb 4: 'float', 360248693Sgleb }) 361248693Sgleb raise NotImplementedError('Invalid encoding: %s' % self) 362248693Sgleb 363248693Sglebclass TypeAliasDef(Def): 364248693Sgleb _is_alias = True 365248693Sgleb def _pp(self, pp): 366248693Sgleb alias = self._alias() 367248693Sgleb # push typedef name 368248693Sgleb if self.name and not alias.name: 369248693Sgleb alias.name = 'T(%s)' % self.name 370248693Sgleb # return type with modifiers 371248693Sgleb return self.type._pp(pp) 372248693Sgleb 373248693Sglebclass EnumerationTypeDef(Def): 374248693Sgleb def _pp(self, pp): 375248693Sgleb return 'enum ' + self._name_opt('UNKNOWN') 376248693Sgleb 377248693Sglebclass ConstTypeDef(AnonymousDef): 378248693Sgleb _is_alias = True 379248693Sgleb def _pp(self, pp): 380248693Sgleb return 'const ' + self.type._pp(pp) 381248693Sgleb 382248693Sglebclass VolatileTypeDef(AnonymousDef): 383248693Sgleb _is_alias = True 384248693Sgleb def _pp(self, pp): 385248693Sgleb return 'volatile ' + self.type._pp(pp) 386248693Sgleb 387275354Sglebclass RestrictTypeDef(AnonymousDef): 388275354Sgleb _is_alias = True 389275354Sgleb def _pp(self, pp): 390275354Sgleb return 'restrict ' + self.type._pp(pp) 391275354Sgleb 392248693Sglebclass ArrayDef(AnonymousDef): 393248693Sgleb def _pp(self, pp): 394248693Sgleb t = pp.run(self.type) 395248693Sgleb assert len(self.subranges) == 1 396248693Sgleb try: 397248693Sgleb sz = int(self.subranges[0].upper_bound) + 1 398248693Sgleb except ValueError: 399248693Sgleb s = re.sub(r'\(.+\)', '', self.subranges[0].upper_bound) 400248693Sgleb sz = int(s) + 1 401248693Sgleb return '%s[%s]' % (t, sz) 402248693Sgleb 403248693Sglebclass ArraySubrangeDef(AnonymousDef): 404248693Sgleb pass 405248693Sgleb 406248693Sglebclass FunctionDef(Def): 407248693Sgleb def _pp(self, pp): 408248693Sgleb result = pp.run(self.result) 409248693Sgleb if not self.params: 410248693Sgleb params = "void" 411248693Sgleb else: 412248693Sgleb params = ', '.join([ pp.run(x) for x in self.params ]) 413248693Sgleb return "%s %s(%s);" % (result, self.name, params) 414248693Sgleb 415248693Sglebclass FunctionTypeDef(Def): 416248693Sgleb def _pp(self, pp): 417248693Sgleb result = pp.run(self.result) 418248693Sgleb if not self.params: 419248693Sgleb params = "void" 420248693Sgleb else: 421248693Sgleb params = ', '.join([ pp.run(x) for x in self.params ]) 422248693Sgleb return "F(%s, %s, (%s))" % (self._name_opt(), result, params) 423248693Sgleb 424248693Sglebclass ParameterDef(Def): 425248693Sgleb def _pp(self, pp): 426248693Sgleb t = pp.run(self.type) 427248693Sgleb return "%s %s" % (t, self._name_opt()) 428248693Sgleb 429275354Sglebclass VariableDef(Def): 430275354Sgleb def _pp(self, pp): 431275354Sgleb t = pp.run(self.type) 432275354Sgleb return "%s %s" % (t, self._name_opt()) 433275354Sgleb 434248693Sgleb# TODO 435248693Sglebclass StructForwardDef(Def): 436248693Sgleb pass 437248693Sgleb 438248693Sglebclass IncompleteDef(Def): 439248693Sgleb def update(self, complete, cache=None): 440248693Sgleb self.complete = complete 441248693Sgleb complete.incomplete = self 442248693Sgleb if cache != None: 443248693Sgleb cached = cache.get(self.id) 444248693Sgleb if cached != None and isinstance(cached, IncompleteDef): 445248693Sgleb cache.replace(self.id, complete) 446248693Sgleb 447248693Sglebclass StructIncompleteDef(IncompleteDef): 448248693Sgleb def _pp(self, pp): 449248693Sgleb return "struct %s" % (self.name,) 450248693Sgleb 451248693Sglebclass UnionIncompleteDef(IncompleteDef): 452248693Sgleb def _pp(self, pp): 453248693Sgleb return "union %s" % (self.name,) 454248693Sgleb 455248693Sglebclass StructDef(Def): 456248693Sgleb def _pp_ex(self, pp, suffix=';'): 457248693Sgleb members = [ pp.run(x) for x in self.members ] 458248693Sgleb return "struct %s { %s }%s" % \ 459248693Sgleb (self._name_opt(), ' '.join(members), suffix) 460248693Sgleb def _pp(self, pp): 461248693Sgleb if self.name: 462248693Sgleb pp.run_nested(self) 463248693Sgleb return "struct %s" % (self.name,) 464248693Sgleb else: 465248693Sgleb return self._pp_ex(pp, suffix='') 466248693Sgleb 467248693Sglebclass UnionDef(Def): 468248693Sgleb def _pp_ex(self, pp, suffix=';'): 469248693Sgleb members = [ pp.run(x) for x in self.members ] 470248693Sgleb return "union %s { %s }%s" % \ 471248693Sgleb (self._name_opt(), ' '.join(members), suffix) 472248693Sgleb def _pp(self, pp): 473248693Sgleb if self.name: 474248693Sgleb pp.run_nested(self) 475248693Sgleb return "union %s" % (self.name,) 476248693Sgleb else: 477248693Sgleb return self._pp_ex(pp, suffix='') 478248693Sgleb 479248693Sglebclass MemberDef(Def): 480248693Sgleb def _pp(self, pp): 481248693Sgleb t = pp.run(self.type) 482248693Sgleb if self.bit_size: 483248693Sgleb bits = ":%s" % self.bit_size 484248693Sgleb else: 485248693Sgleb bits = "" 486248693Sgleb return "%s %s%s;" % (t, self._name_opt(), bits) 487248693Sgleb 488248693Sglebclass Dwarf(object): 489248693Sgleb 490248693Sgleb cmpcache = Cache(enabled=Config.cmpcache_enabled) 491248693Sgleb 492248693Sgleb def __init__(self, dump): 493248693Sgleb self.dump = dump 494248693Sgleb 495248693Sgleb def _build_optarg_type(self, praw): 496248693Sgleb type = praw.optarg('type', Void()) 497248693Sgleb if type != Void(): 498248693Sgleb type = self.buildref(praw.unit, type) 499248693Sgleb return type 500248693Sgleb 501248693Sgleb def build_subprogram(self, raw): 502248693Sgleb if raw.optname == None: 503248693Sgleb raw.setname('SUBPROGRAM_NONAME_' + raw.arg('low_pc')); 504248693Sgleb params = [ self.build(x) for x in raw.nested ] 505248693Sgleb result = self._build_optarg_type(raw) 506248693Sgleb return FunctionDef(raw.id, raw.name, params=params, result=result) 507248693Sgleb 508275354Sgleb def build_variable(self, raw): 509275354Sgleb type = self._build_optarg_type(raw) 510275354Sgleb return VariableDef(raw.id, raw.optname, type=type) 511275354Sgleb 512248693Sgleb def build_subroutine_type(self, raw): 513248693Sgleb params = [ self.build(x) for x in raw.nested ] 514248693Sgleb result = self._build_optarg_type(raw) 515248693Sgleb return FunctionTypeDef(raw.id, raw.optname, params=params, result=result) 516248693Sgleb 517248693Sgleb def build_formal_parameter(self, raw): 518248693Sgleb type = self._build_optarg_type(raw) 519248693Sgleb return ParameterDef(raw.id, raw.optname, type=type) 520248693Sgleb 521248693Sgleb def build_pointer_type(self, raw): 522248693Sgleb type = self._build_optarg_type(raw) 523248693Sgleb return PointerDef(raw.id, type=type) 524248693Sgleb 525248693Sgleb def build_member(self, raw): 526248693Sgleb type = self.buildref(raw.unit, raw.arg('type')) 527248693Sgleb return MemberDef(raw.id, raw.name, type=type, 528248693Sgleb bit_size=raw.optarg('bit_size', None)) 529248693Sgleb 530248693Sgleb def build_structure_type(self, raw): 531248693Sgleb incomplete = raw.unit.incomplete.get(raw.id) 532248693Sgleb if incomplete == None: 533248693Sgleb incomplete = StructIncompleteDef(raw.id, raw.optname) 534248693Sgleb raw.unit.incomplete.put(raw.id, incomplete) 535248693Sgleb else: 536248693Sgleb return incomplete 537248693Sgleb members = [ self.build(x) for x in raw.nested ] 538248693Sgleb byte_size = raw.optarg('byte_size', None) 539248693Sgleb if byte_size == None: 540248693Sgleb obj = StructForwardDef(raw.id, raw.name, members=members, 541248693Sgleb forcename=raw.name) 542248693Sgleb obj = StructDef(raw.id, raw.optname, members=members, 543248693Sgleb byte_size=byte_size) 544248693Sgleb incomplete.update(obj, cache=raw.unit.cache) 545248693Sgleb return obj 546248693Sgleb 547248693Sgleb def build_union_type(self, raw): 548248693Sgleb incomplete = raw.unit.incomplete.get(raw.id) 549248693Sgleb if incomplete == None: 550248693Sgleb incomplete = UnionIncompleteDef(raw.id, raw.optname) 551248693Sgleb raw.unit.incomplete.put(raw.id, incomplete) 552248693Sgleb else: 553248693Sgleb return incomplete 554248693Sgleb members = [ self.build(x) for x in raw.nested ] 555248693Sgleb byte_size = raw.optarg('byte_size', None) 556248693Sgleb obj = UnionDef(raw.id, raw.optname, members=members, 557248693Sgleb byte_size=byte_size) 558248693Sgleb obj.incomplete = incomplete 559248693Sgleb incomplete.complete = obj 560248693Sgleb return obj 561248693Sgleb 562248693Sgleb def build_typedef(self, raw): 563248693Sgleb type = self._build_optarg_type(raw) 564248693Sgleb return TypeAliasDef(raw.id, raw.name, type=type) 565248693Sgleb 566248693Sgleb def build_const_type(self, raw): 567248693Sgleb type = self._build_optarg_type(raw) 568248693Sgleb return ConstTypeDef(raw.id, type=type) 569248693Sgleb 570248693Sgleb def build_volatile_type(self, raw): 571248693Sgleb type = self._build_optarg_type(raw) 572248693Sgleb return VolatileTypeDef(raw.id, type=type) 573248693Sgleb 574275354Sgleb def build_restrict_type(self, raw): 575275354Sgleb type = self._build_optarg_type(raw) 576275354Sgleb return RestrictTypeDef(raw.id, type=type) 577275354Sgleb 578248693Sgleb def build_enumeration_type(self, raw): 579248693Sgleb # TODO handle DW_TAG_enumerator ??? 580248693Sgleb return EnumerationTypeDef(raw.id, name=raw.optname, 581248693Sgleb byte_size=raw.arg('byte_size')) 582248693Sgleb 583248693Sgleb def build_base_type(self, raw): 584248693Sgleb return BaseTypeDef(raw.id, raw.optname, 585248693Sgleb byte_size=raw.arg('byte_size'), encoding=raw.arg('encoding')) 586248693Sgleb 587248693Sgleb def build_array_type(self, raw): 588248693Sgleb type = self.buildref(raw.unit, raw.arg('type')) 589248693Sgleb subranges = [ self.build(x) for x in raw.nested ] 590248693Sgleb return ArrayDef(raw.id, type=type, subranges=subranges) 591248693Sgleb 592248693Sgleb def build_subrange_type(self, raw): 593248693Sgleb type = self.buildref(raw.unit, raw.arg('type')) 594248693Sgleb return ArraySubrangeDef(raw.id, type=type, 595248693Sgleb upper_bound=raw.optarg('upper_bound', 0)) 596248693Sgleb 597248693Sgleb def build_unspecified_parameters(self, raw): 598248693Sgleb return VarArgs(raw.id) 599248693Sgleb 600248693Sgleb def _get_id(self, id): 601248693Sgleb try: 602248693Sgleb return int(id) 603248693Sgleb except ValueError: 604248693Sgleb if (id.startswith('<') and id.endswith('>')): 605275354Sgleb return int(id[1:-1], 0) 606248693Sgleb else: 607248693Sgleb raise ValueError("Invalid dwarf id: %s" % id) 608248693Sgleb 609248693Sgleb def build(self, raw): 610248693Sgleb obj = raw.unit.cache.get(raw.id) 611248693Sgleb if obj != None: 612248693Sgleb return obj 613248693Sgleb builder_name = raw.tag.replace('DW_TAG_', 'build_') 614248693Sgleb try: 615248693Sgleb builder = getattr(self, builder_name) 616248693Sgleb except AttributeError: 617248693Sgleb raise AttributeError("Unknown dwarf tag: %s" % raw) 618248693Sgleb obj = builder(raw) 619248693Sgleb raw.unit.cache.put(obj.id, obj) 620248693Sgleb return obj 621248693Sgleb 622248693Sgleb def buildref(self, unit, id): 623248693Sgleb id = self._get_id(id) 624248693Sgleb raw = unit.tags[id] 625248693Sgleb obj = self.build(raw) 626248693Sgleb return obj 627248693Sgleb 628248693Sgleb# }}} 629248693Sgleb 630248693Sglebclass Shlib(object): 631248693Sgleb def __init__(self, libfile): 632248693Sgleb self.libfile = libfile 633248693Sgleb self.versions = {} 634248693Sgleb self.alias_syms = {} 635248693Sgleb 636248693Sgleb def parse_objdump(self): 637248693Sgleb objdump = ObjdumpParser(self.libfile) 638248693Sgleb objdump.run() 639248693Sgleb for p in objdump.dynamic_symbols: 640248693Sgleb vername = p['ver'] 641248693Sgleb if vername.startswith('(') and vername.endswith(')'): 642248693Sgleb vername = vername[1:-1] 643248693Sgleb if not Config.version_filter.match(vername): 644248693Sgleb continue 645248693Sgleb if not Config.symbol_filter.match(p['symbol']): 646248693Sgleb continue 647248693Sgleb sym = Symbol(p['symbol'], p['offset'], vername, self) 648291036Srodrigc if vername not in self.versions: 649248693Sgleb self.versions[vername] = VersionMap(vername) 650248693Sgleb self.versions[vername].append(sym) 651248693Sgleb if Config.alias_prefixes: 652248693Sgleb self.local_offsetmap = objdump.local_offsetmap 653248693Sgleb for p in objdump.local_symbols: 654248693Sgleb for prefix in Config.alias_prefixes: 655248693Sgleb if not p['symbol'].startswith(prefix): 656248693Sgleb continue 657248693Sgleb alias = SymbolAlias(p['symbol'], prefix, p['offset']) 658291036Srodrigc if alias.name in self.alias_syms: 659248693Sgleb prevalias = self.alias_syms[alias.name] 660248693Sgleb if alias.name != prevalias.name or \ 661248693Sgleb alias.offset != prevalias.offset: 662248693Sgleb warn(Config.w_alias, "Symbol alias is " \ 663248693Sgleb "already defined: %s: %s at %08x -- %s at %08x" % \ 664248693Sgleb (alias.alias, alias.name, alias.offset, 665248693Sgleb prevalias.name, prevalias.offset)) 666248693Sgleb self.alias_syms[alias.name] = alias 667248693Sgleb 668248693Sgleb def parse_dwarfdump(self): 669248693Sgleb dwarfdump = DwarfdumpParser(self.libfile) 670248693Sgleb def lookup(sym): 671248693Sgleb raw = None 672248693Sgleb try: 673248693Sgleb raw = dwarfdump.offsetmap[sym.offset] 674248693Sgleb except: 675248693Sgleb try: 676248693Sgleb localnames = self.local_offsetmap[sym.offset] 677248693Sgleb localnames.sort(key=lambda x: -len(x)) 678248693Sgleb for localname in localnames: 679291036Srodrigc if localname not in self.alias_syms: 680248693Sgleb continue 681248693Sgleb alias = self.alias_syms[localname] 682248693Sgleb raw = dwarfdump.offsetmap[alias.offset] 683248693Sgleb break 684248693Sgleb except: 685248693Sgleb pass 686248693Sgleb return raw 687248693Sgleb dwarfdump.run() 688248693Sgleb dwarf = Dwarf(dwarfdump) 689248693Sgleb for ver in self.versions.values(): 690248693Sgleb for sym in ver.symbols.values(): 691248693Sgleb raw = lookup(sym); 692248693Sgleb if not raw: 693248693Sgleb warn(Config.w_symbol, "Symbol %s (%s) not found at offset 0x%x" % \ 694248693Sgleb (sym.name_ver, self.libfile, sym.offset)) 695248693Sgleb continue 696248693Sgleb if Config.verbose >= 3: 697248693Sgleb print "Parsing symbol %s (%s)" % (sym.name_ver, self.libfile) 698248693Sgleb sym.definition = dwarf.build(raw) 699248693Sgleb 700248693Sgleb def parse(self): 701248693Sgleb if not os.path.isfile(self.libfile): 702248693Sgleb print >> sys.stderr, ("No such file: %s" % self.libfile) 703248693Sgleb sys.exit(1) 704248693Sgleb self.parse_objdump() 705248693Sgleb self.parse_dwarfdump() 706248693Sgleb 707248693Sgleb# {{{ parsers 708248693Sgleb 709248693Sglebclass Parser(object): 710248693Sgleb def __init__(self, proc): 711248693Sgleb self.proc = proc 712248693Sgleb self.parser = self.parse_begin 713248693Sgleb 714248693Sgleb def run(self): 715248693Sgleb fd = os.popen(self.proc, 'r') 716248693Sgleb while True: 717248693Sgleb line = fd.readline() 718248693Sgleb if (not line): 719248693Sgleb break 720248693Sgleb line = line.strip() 721248693Sgleb if (line): 722248693Sgleb self.parser(line) 723248693Sgleb err = fd.close() 724248693Sgleb if err: 725248693Sgleb print >> sys.stderr, ("Execution failed: %s" % self.proc) 726248693Sgleb sys.exit(2) 727248693Sgleb 728248693Sgleb def parse_begin(self, line): 729248693Sgleb print(line) 730248693Sgleb 731248693Sglebclass ObjdumpParser(Parser): 732248693Sgleb 733248693Sgleb re_header = re.compile('(?P<table>\w*)\s*SYMBOL TABLE:') 734248693Sgleb 735248693Sgleb re_local_symbol = re.compile('(?P<offset>[0-9a-fA-F]+)\s+(?P<bind>\w+)\s+(?P<type>\w+)\s+(?P<section>[^\s]+)\s+(?P<foffset>[0-9a-fA-F]+)\s*(?P<symbol>[^\s]*)') 736248693Sgleb re_lame_symbol = re.compile('(?P<offset>[0-9a-fA-F]+)\s+(?P<bind>\w+)\s+\*[A-Z]+\*') 737248693Sgleb 738248693Sgleb re_dynamic_symbol = re.compile('(?P<offset>[0-9a-fA-F]+)\s+(?P<bind>\w+)\s+(?P<type>\w+)\s+(?P<section>[^\s]+)\s+(?P<foffset>[0-9a-fA-F]+)\s*(?P<ver>[^\s]*)\s*(?P<symbol>[^\s]*)') 739248693Sgleb 740248693Sgleb def __init__(self, libfile): 741248693Sgleb Parser.__init__(self, "%s -wtT %s" % (Config.objdump, libfile)) 742248693Sgleb self.dynamic_symbols = [] 743248693Sgleb self.local_symbols = [] 744248693Sgleb self.local_offsetmap = {} 745248693Sgleb 746248693Sgleb def parse_begin(self, line): 747248693Sgleb self.parse_header(line) 748248693Sgleb 749248693Sgleb def add_symbol(self, table, symbol, offsetmap = None): 750248693Sgleb offset = int(symbol['offset'], 16); 751248693Sgleb symbol['offset'] = offset 752248693Sgleb if (offset == 0): 753248693Sgleb return 754248693Sgleb table.append(symbol) 755248693Sgleb if offsetmap != None: 756291036Srodrigc if offset not in offsetmap: 757248693Sgleb offsetmap[offset] = [symbol['symbol']] 758248693Sgleb else: 759248693Sgleb offsetmap[offset].append(symbol['symbol']) 760248693Sgleb 761248693Sgleb def parse_header(self, line): 762248693Sgleb m = self.re_header.match(line) 763248693Sgleb if (m): 764248693Sgleb table = m.group('table') 765248693Sgleb if (table == "DYNAMIC"): 766248693Sgleb self.parser = self.parse_dynamic 767248693Sgleb elif table == '': 768248693Sgleb self.parser = self.parse_local 769248693Sgleb else: 770248693Sgleb raise ValueError("Invalid symbol table: %s" % table) 771248693Sgleb return True 772248693Sgleb return False 773248693Sgleb 774248693Sgleb def parse_local(self, line): 775248693Sgleb if (self.parse_header(line)): 776248693Sgleb return 777248693Sgleb if (self.re_lame_symbol.match(line)): 778248693Sgleb return 779248693Sgleb m = self.re_local_symbol.match(line) 780248693Sgleb if (not m): 781248693Sgleb return 782248693Sgleb #raise ValueError("Invalid symbol definition: %s" % line) 783248693Sgleb p = m.groupdict() 784248693Sgleb if (p['symbol'] and p['symbol'].find('@') == -1): 785248693Sgleb self.add_symbol(self.local_symbols, p, self.local_offsetmap); 786248693Sgleb 787248693Sgleb def parse_dynamic(self, line): 788248693Sgleb if (self.parse_header(line)): 789248693Sgleb return 790248693Sgleb if (self.re_lame_symbol.match(line)): 791248693Sgleb return 792248693Sgleb m = self.re_dynamic_symbol.match(line) 793248693Sgleb if (not m): 794248693Sgleb raise ValueError("Invalid symbol definition: %s" % line) 795248693Sgleb p = m.groupdict() 796248693Sgleb if (p['symbol'] and p['ver']): 797248693Sgleb self.add_symbol(self.dynamic_symbols, p); 798248693Sgleb 799248693Sglebclass DwarfdumpParser(Parser): 800248693Sgleb 801248693Sgleb tagcache_stats = Cache.CacheStats() 802248693Sgleb 803248693Sgleb class Unit(object): 804248693Sgleb def __init__(self): 805248693Sgleb self.cache = Cache(enabled=Config.dwarfcache_enabled, 806248693Sgleb stats=DwarfdumpParser.tagcache_stats) 807248693Sgleb self.incomplete = Cache() 808248693Sgleb self.tags = {} 809248693Sgleb 810248693Sgleb class Tag(object): 811248693Sgleb def __init__(self, unit, data): 812248693Sgleb self.unit = unit 813275354Sgleb self.id = int(data['id'], 0) 814248693Sgleb self.level = int(data['level']) 815248693Sgleb self.tag = data['tag'] 816248693Sgleb self.args = {} 817248693Sgleb self.nested = [] 818248693Sgleb 819248693Sgleb @property 820248693Sgleb def name(self): 821248693Sgleb return self.arg('name') 822248693Sgleb 823248693Sgleb @property 824248693Sgleb def optname(self): 825248693Sgleb return self.optarg('name', None) 826248693Sgleb 827248693Sgleb def setname(self, name): 828248693Sgleb self.args['DW_AT_name'] = name 829248693Sgleb 830248693Sgleb def arg(self, a): 831248693Sgleb name = 'DW_AT_' + a 832248693Sgleb try: 833248693Sgleb return self.args[name] 834248693Sgleb except KeyError: 835248693Sgleb raise KeyError("Argument '%s' not found in %s: %s" % 836248693Sgleb (name, self, self.args)) 837248693Sgleb 838248693Sgleb def optarg(self, a, default): 839248693Sgleb try: 840248693Sgleb return self.arg(a) 841248693Sgleb except KeyError: 842248693Sgleb return default 843248693Sgleb 844248693Sgleb def __repr__(self): 845248693Sgleb return "Tag(%d, %d, %s)" % (self.level, self.id, self.tag) 846248693Sgleb 847275354Sgleb re_header = re.compile('<(?P<level>\d+)><(?P<id>[0xX0-9a-fA-F]+(?:\+(0[xX])?[0-9a-fA-F]+)?)><(?P<tag>\w+)>') 848248693Sgleb re_argname = re.compile('(?P<arg>\w+)<') 849248693Sgleb re_argunknown = re.compile('<Unknown AT value \w+><[^<>]+>') 850248693Sgleb 851248693Sgleb skip_tags = set([ 852248693Sgleb 'DW_TAG_lexical_block', 853248693Sgleb 'DW_TAG_inlined_subroutine', 854248693Sgleb 'DW_TAG_label', 855248693Sgleb 'DW_TAG_variable', 856248693Sgleb ]) 857248693Sgleb 858275354Sgleb external_tags = set([ 859275354Sgleb 'DW_TAG_variable', 860275354Sgleb ]) 861275354Sgleb 862248693Sgleb def __init__(self, libfile): 863248693Sgleb Parser.__init__(self, "%s -di %s" % (Config.dwarfdump, libfile)) 864248693Sgleb self.current_unit = None 865248693Sgleb self.offsetmap = {} 866248693Sgleb self.stack = [] 867248693Sgleb 868248693Sgleb def parse_begin(self, line): 869248693Sgleb if line == '.debug_info': 870248693Sgleb self.parser = self.parse_debuginfo 871248693Sgleb else: 872248693Sgleb raise ValueError("Invalid dwarfdump header: %s" % line) 873248693Sgleb 874248693Sgleb def parse_argvalue(self, args): 875248693Sgleb assert args.startswith('<') 876248693Sgleb i = 1 877248693Sgleb cnt = 1 878248693Sgleb while i < len(args) and args[i]: 879248693Sgleb if args[i] == '<': 880248693Sgleb cnt += 1 881248693Sgleb elif args[i] == '>': 882248693Sgleb cnt -= 1 883248693Sgleb if cnt == 0: 884248693Sgleb break 885248693Sgleb i = i + 1 886248693Sgleb value = args[1:i] 887248693Sgleb args = args[i+1:] 888248693Sgleb return (args, value) 889248693Sgleb 890248693Sgleb def parse_arg(self, tag, args): 891248693Sgleb m = self.re_argname.match(args) 892248693Sgleb if not m: 893248693Sgleb m = self.re_argunknown.match(args) 894248693Sgleb if not m: 895248693Sgleb raise ValueError("Invalid dwarfdump: couldn't parse arguments: %s" % 896248693Sgleb args) 897248693Sgleb args = args[len(m.group(0)):].lstrip() 898248693Sgleb return args 899248693Sgleb argname = m.group('arg') 900248693Sgleb args = args[len(argname):] 901248693Sgleb value = [] 902248693Sgleb while len(args) > 0 and args.startswith('<'): 903248693Sgleb (args, v) = self.parse_argvalue(args) 904248693Sgleb value.append(v) 905248693Sgleb args = args.lstrip() 906248693Sgleb if len(value) == 1: 907248693Sgleb value = value[0] 908248693Sgleb tag.args[argname] = value 909248693Sgleb return args 910248693Sgleb 911248693Sgleb def parse_debuginfo(self, line): 912248693Sgleb m = self.re_header.match(line) 913248693Sgleb if not m: 914248693Sgleb raise ValueError("Invalid dwarfdump: %s" % line) 915248693Sgleb if m.group('level') == '0': 916248693Sgleb self.current_unit = DwarfdumpParser.Unit() 917248693Sgleb return 918248693Sgleb tag = DwarfdumpParser.Tag(self.current_unit, m.groupdict()) 919248693Sgleb args = line[len(m.group(0)):].lstrip() 920248693Sgleb while args: 921248693Sgleb args = self.parse_arg(tag, args) 922248693Sgleb tag.unit.tags[tag.id] = tag 923275354Sgleb def parse_offset(tag): 924291036Srodrigc if 'DW_AT_low_pc' in tag.args: 925275354Sgleb return int(tag.args['DW_AT_low_pc'], 16) 926291036Srodrigc elif 'DW_AT_location' in tag.args: 927275354Sgleb location = tag.args['DW_AT_location'] 928275354Sgleb if location.startswith('DW_OP_addr'): 929275354Sgleb return int(location.replace('DW_OP_addr', ''), 16) 930275354Sgleb return None 931275354Sgleb offset = parse_offset(tag) 932275354Sgleb if offset is not None and \ 933275354Sgleb (tag.tag not in DwarfdumpParser.skip_tags or \ 934291036Srodrigc ('DW_AT_external' in tag.args and \ 935275354Sgleb tag.tag in DwarfdumpParser.external_tags)): 936291036Srodrigc if offset in self.offsetmap: 937248693Sgleb raise ValueError("Dwarf dump parse error: " + 938248693Sgleb "symbol is aleady defined at offset 0x%x" % offset) 939248693Sgleb self.offsetmap[offset] = tag 940248693Sgleb if len(self.stack) > 0: 941248693Sgleb prev = self.stack.pop() 942248693Sgleb while prev.level >= tag.level and len(self.stack) > 0: 943248693Sgleb prev = self.stack.pop() 944248693Sgleb if prev.level < tag.level: 945248693Sgleb assert prev.level == tag.level - 1 946248693Sgleb # TODO check DW_AT_sibling ??? 947248693Sgleb if tag.tag not in DwarfdumpParser.skip_tags: 948248693Sgleb prev.nested.append(tag) 949248693Sgleb self.stack.append(prev) 950248693Sgleb self.stack.append(tag) 951248693Sgleb assert len(self.stack) == tag.level 952248693Sgleb 953248693Sgleb# }}} 954248693Sgleb 955248693Sglebdef list_str(l): 956248693Sgleb l = [ str(x) for x in l ] 957248693Sgleb l.sort() 958248693Sgleb return ', '.join(l) 959248693Sgleb 960248693Sglebdef names_ver_str(vername, names): 961248693Sgleb return list_str([ x + "@" + vername for x in names ]) 962248693Sgleb 963248693Sglebdef common_symbols(origlib, newlib): 964248693Sgleb result = [] 965248693Sgleb verdiff = ListDiff(origlib.versions.keys(), newlib.versions.keys()) 966248693Sgleb if Config.verbose >= 1: 967248693Sgleb print 'Original versions: ', list_str(verdiff.orig) 968248693Sgleb print 'New versions: ', list_str(verdiff.new) 969248693Sgleb for vername in verdiff.added: 970248693Sgleb print 'Added version: ', vername 971248693Sgleb print ' Added symbols: ', \ 972248693Sgleb names_ver_str(vername, newlib.versions[vername].names()) 973248693Sgleb for vername in verdiff.removed: 974248693Sgleb print 'Removed version: ', vername 975248693Sgleb print ' Removed symbols: ', \ 976248693Sgleb names_ver_str(vername, origlib.versions[vername].names()) 977248693Sgleb added = [] 978248693Sgleb removed = [] 979248693Sgleb for vername in verdiff.common: 980248693Sgleb origver = origlib.versions[vername] 981248693Sgleb newver = newlib.versions[vername] 982248693Sgleb namediff = ListDiff(origver.names(), newver.names()) 983248693Sgleb if namediff.added: 984248693Sgleb added.append(names_ver_str(vername, namediff.added)) 985248693Sgleb if namediff.removed: 986248693Sgleb removed.append(names_ver_str(vername, namediff.removed)) 987248693Sgleb commonver = VersionMap(vername) 988248693Sgleb result.append(commonver) 989248693Sgleb for n in namediff.common: 990248693Sgleb sym = CommonSymbol(origver.symbols[n], newver.symbols[n]) 991248693Sgleb commonver.append(sym) 992248693Sgleb if added: 993248693Sgleb print 'Added symbols:' 994248693Sgleb for i in added: 995248693Sgleb print ' ', i 996248693Sgleb if removed: 997248693Sgleb print 'Removed symbols:' 998248693Sgleb for i in removed: 999248693Sgleb print ' ', i 1000248693Sgleb return result 1001248693Sgleb 1002248693Sglebdef cmp_symbols(commonver): 1003248693Sgleb for ver in commonver: 1004248693Sgleb names = ver.names(); 1005248693Sgleb names.sort() 1006248693Sgleb for symname in names: 1007248693Sgleb sym = ver.symbols[symname] 1008275354Sgleb missing = sym.origsym.definition is None or sym.newsym.definition is None 1009275354Sgleb match = not missing and sym.origsym.definition == sym.newsym.definition 1010248693Sgleb if not match: 1011248693Sgleb App.result_code = 1 1012248693Sgleb if Config.verbose >= 1 or not match: 1013275354Sgleb if missing: 1014275354Sgleb print '%s: missing definition' % \ 1015275354Sgleb (sym.origsym.name_ver,) 1016275354Sgleb continue 1017248693Sgleb print '%s: definitions %smatch' % \ 1018248693Sgleb (sym.origsym.name_ver, "" if match else "mis") 1019248693Sgleb if Config.dump or (not match and not Config.no_dump): 1020248693Sgleb for x in [(sym.origsym, Config.origfile), 1021248693Sgleb (sym.newsym, Config.newfile)]: 1022248693Sgleb xsym = x[0] 1023248693Sgleb xout = x[1].out 1024248693Sgleb if not xsym.definition: 1025248693Sgleb print >> xout, '\n// Definition not found: %s %s' % \ 1026248693Sgleb (xsym.name_ver, xsym.lib.libfile) 1027248693Sgleb continue 1028248693Sgleb print >> xout, '\n// Definitions mismatch: %s %s' % \ 1029248693Sgleb (xsym.name_ver, xsym.lib.libfile) 1030248693Sgleb pp = PrettyPrinter() 1031248693Sgleb pp.run(xsym.definition) 1032248693Sgleb for i in pp.nested(): 1033248693Sgleb print >> xout, i 1034248693Sgleb print >> xout, pp.result() 1035248693Sgleb 1036248693Sglebdef dump_symbols(commonver): 1037248693Sgleb class SymbolDump(object): 1038248693Sgleb def __init__(self, io_conf): 1039248693Sgleb self.io_conf = io_conf 1040248693Sgleb self.pp = PrettyPrinter() 1041248693Sgleb self.res = [] 1042248693Sgleb def run(self, sym): 1043248693Sgleb r = self.pp.run(sym.definition) 1044248693Sgleb self.res.append('/* %s@%s */ %s' % (sym.name, sym.version, r)) 1045248693Sgleb def finish(self): 1046248693Sgleb print >> self.io_conf.out, '\n// Symbol dump: version %s, library %s' % \ 1047248693Sgleb (ver.name, self.io_conf.filename) 1048248693Sgleb for i in self.pp.nested(): 1049248693Sgleb print >> self.io_conf.out, i 1050248693Sgleb print >> self.io_conf.out, '' 1051248693Sgleb for i in self.res: 1052248693Sgleb print >> self.io_conf.out, i 1053248693Sgleb for ver in commonver: 1054248693Sgleb names = sorted(ver.names()); 1055248693Sgleb d_orig = SymbolDump(Config.origfile) 1056248693Sgleb d_new = SymbolDump(Config.newfile) 1057248693Sgleb for symname in names: 1058248693Sgleb sym = ver.symbols[symname] 1059248693Sgleb if not sym.origsym.definition or not sym.newsym.definition: 1060248693Sgleb # XXX 1061248693Sgleb warn(Config.w_symbol, 'Missing symbol definition: %s@%s' % \ 1062248693Sgleb (symname, ver.name)) 1063248693Sgleb continue 1064248693Sgleb d_orig.run(sym.origsym) 1065248693Sgleb d_new.run(sym.newsym) 1066248693Sgleb d_orig.finish() 1067248693Sgleb d_new.finish() 1068248693Sgleb 1069248693Sglebif __name__ == '__main__': 1070248693Sgleb Config.init() 1071248693Sgleb parser = optparse.OptionParser(usage="usage: %prog origlib newlib", 1072248693Sgleb version="%prog " + Config.version) 1073248693Sgleb parser.add_option('-v', '--verbose', action='count', 1074248693Sgleb help="verbose mode, may be specified several times") 1075248693Sgleb parser.add_option('--alias-prefix', action='append', 1076248693Sgleb help="name prefix to try for symbol alias lookup", metavar="STR") 1077248693Sgleb parser.add_option('--dump', action='store_true', 1078248693Sgleb help="dump symbol definitions") 1079248693Sgleb parser.add_option('--no-dump', action='store_true', 1080248693Sgleb help="disable dump for mismatched symbols") 1081248693Sgleb parser.add_option('--out-orig', action='store', 1082248693Sgleb help="result output file for original library", metavar="ORIGFILE") 1083248693Sgleb parser.add_option('--out-new', action='store', 1084248693Sgleb help="result output file for new library", metavar="NEWFILE") 1085275354Sgleb parser.add_option('--dwarfdump', action='store', 1086275354Sgleb help="path to dwarfdump executable", metavar="DWARFDUMP") 1087275354Sgleb parser.add_option('--objdump', action='store', 1088275354Sgleb help="path to objdump executable", metavar="OBJDUMP") 1089248693Sgleb parser.add_option('--exclude-ver', action='append', metavar="RE") 1090248693Sgleb parser.add_option('--include-ver', action='append', metavar="RE") 1091248693Sgleb parser.add_option('--exclude-sym', action='append', metavar="RE") 1092248693Sgleb parser.add_option('--include-sym', action='append', metavar="RE") 1093275354Sgleb parser.add_option('--no-exclude-sym-default', action='store_true', 1094275354Sgleb help="don't exclude special symbols like _init, _end, __bss_start") 1095248693Sgleb for opt in ['alias', 'cached', 'symbol']: 1096248693Sgleb parser.add_option("--w-" + opt, 1097248693Sgleb action="store_true", dest="w_" + opt) 1098248693Sgleb parser.add_option("--w-no-" + opt, 1099248693Sgleb action="store_false", dest="w_" + opt) 1100248693Sgleb (opts, args) = parser.parse_args() 1101248693Sgleb 1102248693Sgleb if len(args) != 2: 1103248693Sgleb parser.print_help() 1104248693Sgleb sys.exit(-1) 1105275354Sgleb if opts.dwarfdump: 1106275354Sgleb Config.dwarfdump = opts.dwarfdump 1107275354Sgleb if opts.objdump: 1108275354Sgleb Config.objdump = opts.objdump 1109248693Sgleb if opts.out_orig: 1110248693Sgleb Config.origfile.init(opts.out_orig) 1111248693Sgleb if opts.out_new: 1112248693Sgleb Config.newfile.init(opts.out_new) 1113248693Sgleb if opts.no_dump: 1114248693Sgleb Config.dump = False 1115248693Sgleb Config.no_dump = True 1116248693Sgleb if opts.dump: 1117248693Sgleb Config.dump = True 1118248693Sgleb Config.no_dump = False 1119248693Sgleb Config.verbose = 1 1120248693Sgleb if opts.verbose: 1121248693Sgleb Config.verbose = opts.verbose 1122248693Sgleb if opts.alias_prefix: 1123248693Sgleb Config.alias_prefixes = opts.alias_prefix 1124248693Sgleb Config.alias_prefixes.sort(key=lambda x: -len(x)) 1125248693Sgleb for (k, v) in ({ '_sym': Config.symbol_filter, 1126248693Sgleb '_ver': Config.version_filter }).items(): 1127248693Sgleb for a in [ 'exclude', 'include' ]: 1128248693Sgleb opt = getattr(opts, a + k) 1129248693Sgleb if opt: 1130248693Sgleb getattr(v, a).extend(opt) 1131275354Sgleb if not opts.no_exclude_sym_default: 1132275354Sgleb Config.symbol_filter.exclude.extend(Config.exclude_sym_default) 1133248693Sgleb Config.version_filter.compile() 1134248693Sgleb Config.symbol_filter.compile() 1135248693Sgleb for w in ['w_alias', 'w_cached', 'w_symbol']: 1136248693Sgleb if hasattr(opts, w): 1137248693Sgleb v = getattr(opts, w) 1138248693Sgleb if v != None: 1139248693Sgleb setattr(Config, w, v) 1140248693Sgleb 1141248693Sgleb (Config.origfile.filename, Config.newfile.filename) = (args[0], args[1]) 1142248693Sgleb 1143248693Sgleb origlib = Shlib(Config.origfile.filename) 1144248693Sgleb origlib.parse() 1145248693Sgleb newlib = Shlib(Config.newfile.filename) 1146248693Sgleb newlib.parse() 1147248693Sgleb 1148248693Sgleb commonver = common_symbols(origlib, newlib) 1149248693Sgleb if Config.dump: 1150248693Sgleb dump_symbols(commonver) 1151248693Sgleb cmp_symbols(commonver) 1152248693Sgleb if Config.verbose >= 4: 1153248693Sgleb print Dwarf.cmpcache.stats.show('Cmp') 1154248693Sgleb print DwarfdumpParser.tagcache_stats.show('Dwarf tag') 1155248693Sgleb 1156248693Sgleb sys.exit(App.result_code) 1157