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