1a1897c0cSGleb Kurtsou#!/usr/bin/env python
2a1897c0cSGleb Kurtsou#-
3a1897c0cSGleb Kurtsou# Copyright (c) 2010 Gleb Kurtsou
4a1897c0cSGleb Kurtsou# All rights reserved.
5a1897c0cSGleb Kurtsou#
6a1897c0cSGleb Kurtsou# Redistribution and use in source and binary forms, with or without
7a1897c0cSGleb Kurtsou# modification, are permitted provided that the following conditions
8a1897c0cSGleb Kurtsou# are met:
9a1897c0cSGleb Kurtsou# 1. Redistributions of source code must retain the above copyright
10a1897c0cSGleb Kurtsou#    notice, this list of conditions and the following disclaimer.
11a1897c0cSGleb Kurtsou# 2. Redistributions in binary form must reproduce the above copyright
12a1897c0cSGleb Kurtsou#    notice, this list of conditions and the following disclaimer in the
13a1897c0cSGleb Kurtsou#    documentation and/or other materials provided with the distribution.
14a1897c0cSGleb Kurtsou#
15a1897c0cSGleb Kurtsou# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16a1897c0cSGleb Kurtsou# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17a1897c0cSGleb Kurtsou# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18a1897c0cSGleb Kurtsou# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19a1897c0cSGleb Kurtsou# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20a1897c0cSGleb Kurtsou# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21a1897c0cSGleb Kurtsou# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22a1897c0cSGleb Kurtsou# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23a1897c0cSGleb Kurtsou# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24a1897c0cSGleb Kurtsou# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25a1897c0cSGleb Kurtsou# SUCH DAMAGE.
26a1897c0cSGleb Kurtsou#
27a1897c0cSGleb Kurtsou
28749f65e3SCraig Rodriguesfrom __future__ import print_function
29a1897c0cSGleb Kurtsouimport os
30a1897c0cSGleb Kurtsouimport sys
31a1897c0cSGleb Kurtsouimport re
32a1897c0cSGleb Kurtsouimport optparse
33a1897c0cSGleb Kurtsou
34a1897c0cSGleb Kurtsouclass Config(object):
35a1897c0cSGleb Kurtsou    version = '0.1'
36a1897c0cSGleb Kurtsou    # controlled by user
37a1897c0cSGleb Kurtsou    verbose = 0
38a1897c0cSGleb Kurtsou    dump = False
39a1897c0cSGleb Kurtsou    no_dump = False
40a1897c0cSGleb Kurtsou    version_filter = None
41a1897c0cSGleb Kurtsou    symbol_filter = None
42a1897c0cSGleb Kurtsou    alias_prefixes = []
43a1897c0cSGleb Kurtsou    # misc opts
44a1897c0cSGleb Kurtsou    objdump = 'objdump'
45a1897c0cSGleb Kurtsou    dwarfdump = 'dwarfdump'
46a1897c0cSGleb Kurtsou    # debug
47a1897c0cSGleb Kurtsou    cmpcache_enabled = True
48a1897c0cSGleb Kurtsou    dwarfcache_enabled = True
49a1897c0cSGleb Kurtsou    w_alias = True
50a1897c0cSGleb Kurtsou    w_cached = False
51a1897c0cSGleb Kurtsou    w_symbol = True
52a1897c0cSGleb Kurtsou
53a1897c0cSGleb Kurtsou    class FileConfig(object):
54a1897c0cSGleb Kurtsou        filename = None
55a1897c0cSGleb Kurtsou        out = sys.stdout
56a1897c0cSGleb Kurtsou        def init(self, outname):
57a1897c0cSGleb Kurtsou            if outname and outname != '-':
58a1897c0cSGleb Kurtsou                self.out = open(outname, "w")
59a1897c0cSGleb Kurtsou
60a1897c0cSGleb Kurtsou    origfile = FileConfig()
61a1897c0cSGleb Kurtsou    newfile = FileConfig()
62a1897c0cSGleb Kurtsou
63c5f8185bSGleb Kurtsou    exclude_sym_default = [
64c5f8185bSGleb Kurtsou            '^__bss_start$',
65c5f8185bSGleb Kurtsou            '^_edata$',
66c5f8185bSGleb Kurtsou            '^_end$',
67c5f8185bSGleb Kurtsou            '^_fini$',
68c5f8185bSGleb Kurtsou            '^_init$',
69c5f8185bSGleb Kurtsou            ]
70c5f8185bSGleb Kurtsou
71a1897c0cSGleb Kurtsou    @classmethod
72a1897c0cSGleb Kurtsou    def init(cls):
73a1897c0cSGleb Kurtsou        cls.version_filter = StrFilter()
74a1897c0cSGleb Kurtsou        cls.symbol_filter = StrFilter()
75a1897c0cSGleb Kurtsou
76a1897c0cSGleb Kurtsouclass App(object):
77a1897c0cSGleb Kurtsou    result_code = 0
78a1897c0cSGleb Kurtsou
79a1897c0cSGleb Kurtsoudef warn(cond, msg):
80a1897c0cSGleb Kurtsou    if cond:
81749f65e3SCraig Rodrigues        print("WARN: " + msg, file=sys.stderr)
82a1897c0cSGleb Kurtsou
83a1897c0cSGleb Kurtsou# {{{ misc
84a1897c0cSGleb Kurtsou
85a1897c0cSGleb Kurtsouclass StrFilter(object):
86a1897c0cSGleb Kurtsou    def __init__(self):
87a1897c0cSGleb Kurtsou        self.exclude = []
88a1897c0cSGleb Kurtsou        self.include = []
89a1897c0cSGleb Kurtsou
90a1897c0cSGleb Kurtsou    def compile(self):
91a1897c0cSGleb Kurtsou        self.re_exclude = [ re.compile(x) for x in self.exclude ]
92a1897c0cSGleb Kurtsou        self.re_include = [ re.compile(x) for x in self.include ]
93a1897c0cSGleb Kurtsou
94a1897c0cSGleb Kurtsou    def match(self, s):
95a1897c0cSGleb Kurtsou        if len(self.re_include):
96a1897c0cSGleb Kurtsou            matched = False
97a1897c0cSGleb Kurtsou            for r in self.re_include:
98a1897c0cSGleb Kurtsou                if r.match(s):
99a1897c0cSGleb Kurtsou                    matched = True
100a1897c0cSGleb Kurtsou                    break
101a1897c0cSGleb Kurtsou            if not matched:
102a1897c0cSGleb Kurtsou                return False
103a1897c0cSGleb Kurtsou        for r in self.re_exclude:
104a1897c0cSGleb Kurtsou            if r.match(s):
105a1897c0cSGleb Kurtsou                return False
106a1897c0cSGleb Kurtsou        return True
107a1897c0cSGleb Kurtsou
108a1897c0cSGleb Kurtsouclass Cache(object):
109a1897c0cSGleb Kurtsou
110a1897c0cSGleb Kurtsou    class CacheStats(object):
111a1897c0cSGleb Kurtsou        def __init__(self):
112a1897c0cSGleb Kurtsou            self.hit = 0
113a1897c0cSGleb Kurtsou            self.miss = 0
114a1897c0cSGleb Kurtsou
115a1897c0cSGleb Kurtsou        def show(self, name):
116a1897c0cSGleb Kurtsou            total = self.hit + self.miss
117a1897c0cSGleb Kurtsou            if total == 0:
118a1897c0cSGleb Kurtsou                ratio = '(undef)'
119a1897c0cSGleb Kurtsou            else:
120a1897c0cSGleb Kurtsou                ratio = '%f' % (self.hit/float(total))
121a1897c0cSGleb Kurtsou            return '%s cache stats: hit: %d; miss: %d; ratio: %s' % \
122a1897c0cSGleb Kurtsou                    (name, self.hit, self.miss, ratio)
123a1897c0cSGleb Kurtsou
124a1897c0cSGleb Kurtsou    def __init__(self, enabled=True, stats=None):
125a1897c0cSGleb Kurtsou        self.enabled = enabled
126a1897c0cSGleb Kurtsou        self.items = {}
127a1897c0cSGleb Kurtsou        if stats == None:
128a1897c0cSGleb Kurtsou            self.stats = Cache.CacheStats()
129a1897c0cSGleb Kurtsou        else:
130a1897c0cSGleb Kurtsou            self.stats = stats
131a1897c0cSGleb Kurtsou
132a1897c0cSGleb Kurtsou    def get(self, id):
133aef675d8SCraig Rodrigues        if self.enabled and id in self.items:
134a1897c0cSGleb Kurtsou            self.stats.hit += 1
135a1897c0cSGleb Kurtsou            return self.items[id]
136a1897c0cSGleb Kurtsou        else:
137a1897c0cSGleb Kurtsou            self.stats.miss += 1
138a1897c0cSGleb Kurtsou            return None
139a1897c0cSGleb Kurtsou
140a1897c0cSGleb Kurtsou    def put(self, id, obj):
141a1897c0cSGleb Kurtsou        if self.enabled:
142aef675d8SCraig Rodrigues            if id in self.items and obj is not self.items[id]:
143a1897c0cSGleb Kurtsou                #raise ValueError("Item is already cached: %d (%s, %s)" %
144a1897c0cSGleb Kurtsou                #        (id, self.items[id], obj))
145a1897c0cSGleb Kurtsou                warn(Config.w_cached, "Item is already cached: %d (%s, %s)" % \
146a1897c0cSGleb Kurtsou                        (id, self.items[id], obj))
147a1897c0cSGleb Kurtsou            self.items[id] = obj
148a1897c0cSGleb Kurtsou
149a1897c0cSGleb Kurtsou    def replace(self, id, obj):
150a1897c0cSGleb Kurtsou        if self.enabled:
151aef675d8SCraig Rodrigues            assert id in self.items
152a1897c0cSGleb Kurtsou            self.items[id] = obj
153a1897c0cSGleb Kurtsou
154a1897c0cSGleb Kurtsouclass ListDiff(object):
155a1897c0cSGleb Kurtsou    def __init__(self, orig, new):
156a1897c0cSGleb Kurtsou        self.orig = set(orig)
157a1897c0cSGleb Kurtsou        self.new = set(new)
158a1897c0cSGleb Kurtsou        self.common = self.orig & self.new
159a1897c0cSGleb Kurtsou        self.added = self.new - self.common
160a1897c0cSGleb Kurtsou        self.removed = self.orig - self.common
161a1897c0cSGleb Kurtsou
162a1897c0cSGleb Kurtsouclass PrettyPrinter(object):
163a1897c0cSGleb Kurtsou    def __init__(self):
164a1897c0cSGleb Kurtsou        self.stack = []
165a1897c0cSGleb Kurtsou
166a1897c0cSGleb Kurtsou    def run_nested(self, obj):
167a1897c0cSGleb Kurtsou        ex = obj._pp_ex(self)
168a1897c0cSGleb Kurtsou        self.stack.append(ex)
169a1897c0cSGleb Kurtsou
170a1897c0cSGleb Kurtsou    def run(self, obj):
171a1897c0cSGleb Kurtsou        self._result = obj._pp(self)
172a1897c0cSGleb Kurtsou        return self._result
173a1897c0cSGleb Kurtsou
174a1897c0cSGleb Kurtsou    def nested(self):
175a1897c0cSGleb Kurtsou        return sorted(set(self.stack))
176a1897c0cSGleb Kurtsou
177a1897c0cSGleb Kurtsou    def result(self):
178a1897c0cSGleb Kurtsou        return self._result;
179a1897c0cSGleb Kurtsou
180a1897c0cSGleb Kurtsou# }}}
181a1897c0cSGleb Kurtsou
182a1897c0cSGleb Kurtsou#{{{ symbols and version maps
183a1897c0cSGleb Kurtsou
184a1897c0cSGleb Kurtsouclass Symbol(object):
185a1897c0cSGleb Kurtsou    def __init__(self, name, offset, version, lib):
186a1897c0cSGleb Kurtsou        self.name = name
187a1897c0cSGleb Kurtsou        self.offset = offset
188a1897c0cSGleb Kurtsou        self.version = version
189a1897c0cSGleb Kurtsou        self.lib = lib
190a1897c0cSGleb Kurtsou        self.definition = None
191a1897c0cSGleb Kurtsou
192a1897c0cSGleb Kurtsou    @property
193a1897c0cSGleb Kurtsou    def name_ver(self):
194a1897c0cSGleb Kurtsou        return self.name + '@' + self.version
195a1897c0cSGleb Kurtsou
196a1897c0cSGleb Kurtsou    def __repr__(self):
197a1897c0cSGleb Kurtsou        return "Symbol(%s, 0x%x, %s)" % (self.name, self.offset, self.version)
198a1897c0cSGleb Kurtsou
199a1897c0cSGleb Kurtsouclass CommonSymbol(object):
200a1897c0cSGleb Kurtsou    def __init__(self, origsym, newsym):
201a1897c0cSGleb Kurtsou        if origsym.name != newsym.name or origsym.version != newsym.version:
202a1897c0cSGleb Kurtsou            raise RuntimeError("Symbols have different names: %s",
203a1897c0cSGleb Kurtsou                    [origsym, newsym])
204a1897c0cSGleb Kurtsou        self.origsym = origsym
205a1897c0cSGleb Kurtsou        self.newsym = newsym
206a1897c0cSGleb Kurtsou        self.name = newsym.name
207a1897c0cSGleb Kurtsou        self.version = newsym.version
208a1897c0cSGleb Kurtsou
209a1897c0cSGleb Kurtsou    def __repr__(self):
210a1897c0cSGleb Kurtsou        return "CommonSymbol(%s, %s)" % (self.name, self.version)
211a1897c0cSGleb Kurtsou
212a1897c0cSGleb Kurtsouclass SymbolAlias(object):
213a1897c0cSGleb Kurtsou    def __init__(self, alias, prefix, offset):
214a1897c0cSGleb Kurtsou        assert alias.startswith(prefix)
215a1897c0cSGleb Kurtsou        self.alias = alias
216a1897c0cSGleb Kurtsou        self.name = alias[len(prefix):]
217a1897c0cSGleb Kurtsou        self.offset = offset
218a1897c0cSGleb Kurtsou
219a1897c0cSGleb Kurtsou    def __repr__(self):
220a1897c0cSGleb Kurtsou        return "SymbolAlias(%s, 0x%x)" % (self.alias, self.offset)
221a1897c0cSGleb Kurtsou
222a1897c0cSGleb Kurtsou
223a1897c0cSGleb Kurtsouclass VersionMap(object):
224a1897c0cSGleb Kurtsou    def __init__(self, name):
225a1897c0cSGleb Kurtsou        self.name = name
226a1897c0cSGleb Kurtsou        self.symbols = {}
227a1897c0cSGleb Kurtsou
228a1897c0cSGleb Kurtsou    def append(self, symbol):
229aef675d8SCraig Rodrigues        if (symbol.name in self.symbols):
230a1897c0cSGleb Kurtsou            raise ValueError("Symbol is already defined %s@%s" %
231a1897c0cSGleb Kurtsou                    (symbol.name, self.name))
232a1897c0cSGleb Kurtsou        self.symbols[symbol.name] = symbol
233a1897c0cSGleb Kurtsou
234a1897c0cSGleb Kurtsou    def names(self):
235a1897c0cSGleb Kurtsou        return self.symbols.keys()
236a1897c0cSGleb Kurtsou
237a1897c0cSGleb Kurtsou    def __repr__(self):
238a1897c0cSGleb Kurtsou        return repr(self.symbols.values())
239a1897c0cSGleb Kurtsou
240a1897c0cSGleb Kurtsou# }}}
241a1897c0cSGleb Kurtsou
242a1897c0cSGleb Kurtsou# {{{ types and definitions
243a1897c0cSGleb Kurtsou
244a1897c0cSGleb Kurtsouclass Def(object):
245a1897c0cSGleb Kurtsou    _is_alias = False
246a1897c0cSGleb Kurtsou
247a1897c0cSGleb Kurtsou    def __init__(self, id, name, **kwargs):
248a1897c0cSGleb Kurtsou        self.id = id
249a1897c0cSGleb Kurtsou        self.name = name
250a1897c0cSGleb Kurtsou        self.attrs = kwargs
251a1897c0cSGleb Kurtsou
252a1897c0cSGleb Kurtsou    def __getattr__(self, attr):
253aef675d8SCraig Rodrigues        if attr not in self.attrs:
254a1897c0cSGleb Kurtsou            raise AttributeError('%s in %s' % (attr, str(self)))
255a1897c0cSGleb Kurtsou        return self.attrs[attr]
256a1897c0cSGleb Kurtsou
257a1897c0cSGleb Kurtsou    def _name_opt(self, default=''):
258a1897c0cSGleb Kurtsou        if not self.name:
259a1897c0cSGleb Kurtsou            return default
260a1897c0cSGleb Kurtsou        return self.name
261a1897c0cSGleb Kurtsou
262a1897c0cSGleb Kurtsou    def _alias(self):
263a1897c0cSGleb Kurtsou        if self._is_alias:
264a1897c0cSGleb Kurtsou            return self.type._alias()
265a1897c0cSGleb Kurtsou        return self
266a1897c0cSGleb Kurtsou
267a1897c0cSGleb Kurtsou    def __cmp__(self, other):
268a1897c0cSGleb Kurtsou        # TODO assert 'self' and 'other' belong to different libraries
269a1897c0cSGleb Kurtsou        #print 'cmp defs: %s, %s' % (self, other)
270a1897c0cSGleb Kurtsou        a = self._alias()
271a1897c0cSGleb Kurtsou        try:
272a1897c0cSGleb Kurtsou            b = other._alias()
273a1897c0cSGleb Kurtsou        except AttributeError:
274a1897c0cSGleb Kurtsou            return 1
275a1897c0cSGleb Kurtsou        r = cmp(a.__class__, b.__class__)
276a1897c0cSGleb Kurtsou        if r == 0:
277a1897c0cSGleb Kurtsou            if a.id != 0 and b.id != 0:
278a1897c0cSGleb Kurtsou                ind = (long(a.id) << 32) + b.id
279a1897c0cSGleb Kurtsou                r = Dwarf.cmpcache.get(ind)
280a1897c0cSGleb Kurtsou                if r != None:
281a1897c0cSGleb Kurtsou                    return r
282a1897c0cSGleb Kurtsou            else:
283a1897c0cSGleb Kurtsou                ind = 0
284a1897c0cSGleb Kurtsou            r = cmp(a.attrs, b.attrs)
285a1897c0cSGleb Kurtsou            if ind != 0:
286a1897c0cSGleb Kurtsou                Dwarf.cmpcache.put(ind, r)
287a1897c0cSGleb Kurtsou        else:
288a1897c0cSGleb Kurtsou            r = 0
289a1897c0cSGleb Kurtsou            #raise RuntimeError('Comparing different classes: %s, %s' %
290a1897c0cSGleb Kurtsou            #        (a.__class__.__name__, b.__class__.__name__))
291a1897c0cSGleb Kurtsou        return r
292a1897c0cSGleb Kurtsou
293a1897c0cSGleb Kurtsou    def __repr__(self):
294a1897c0cSGleb Kurtsou        p = []
295a1897c0cSGleb Kurtsou        if hasattr(self, 'name'):
296a1897c0cSGleb Kurtsou            p.append("name=%s" % self.name)
297a1897c0cSGleb Kurtsou        for (k, v) in self.attrs.items():
298a1897c0cSGleb Kurtsou            if isinstance(v, Def):
299a1897c0cSGleb Kurtsou                v = v.__class__.__name__ + '(...)'
300a1897c0cSGleb Kurtsou            p.append("%s=%s" % (k, v))
301a1897c0cSGleb Kurtsou        return self.__class__.__name__ + '(' + ', '.join(p) + ')'
302a1897c0cSGleb Kurtsou
303a1897c0cSGleb Kurtsou    def _mapval(self, param, vals):
304a1897c0cSGleb Kurtsou        if param not in vals.keys():
305a1897c0cSGleb Kurtsou            raise NotImplementedError("Invalid value '%s': %s" %
306a1897c0cSGleb Kurtsou                    (param, str(self)))
307a1897c0cSGleb Kurtsou        return vals[param]
308a1897c0cSGleb Kurtsou
309a1897c0cSGleb Kurtsou    def _pp_ex(self, pp):
310a1897c0cSGleb Kurtsou        raise NotImplementedError('Extended pretty print not implemeted: %s' %
311a1897c0cSGleb Kurtsou                str(self))
312a1897c0cSGleb Kurtsou
313a1897c0cSGleb Kurtsou    def _pp(self, pp):
314a1897c0cSGleb Kurtsou        raise NotImplementedError('Pretty print not implemeted: %s' % str(self))
315a1897c0cSGleb Kurtsou
316a1897c0cSGleb Kurtsouclass AnonymousDef(Def):
317a1897c0cSGleb Kurtsou    def __init__(self, id, **kwargs):
318a1897c0cSGleb Kurtsou        Def.__init__(self, id, None, **kwargs)
319a1897c0cSGleb Kurtsou
320a1897c0cSGleb Kurtsouclass Void(AnonymousDef):
321a1897c0cSGleb Kurtsou    _instance = None
322a1897c0cSGleb Kurtsou
323a1897c0cSGleb Kurtsou    def __new__(cls, *args, **kwargs):
324a1897c0cSGleb Kurtsou        if not cls._instance:
325a1897c0cSGleb Kurtsou            cls._instance = super(Void, cls).__new__(
326a1897c0cSGleb Kurtsou                    cls, *args, **kwargs)
327a1897c0cSGleb Kurtsou        return cls._instance
328a1897c0cSGleb Kurtsou
329a1897c0cSGleb Kurtsou    def __init__(self):
330a1897c0cSGleb Kurtsou        AnonymousDef.__init__(self, 0)
331a1897c0cSGleb Kurtsou
332a1897c0cSGleb Kurtsou    def _pp(self, pp):
333a1897c0cSGleb Kurtsou        return "void"
334a1897c0cSGleb Kurtsou
335a1897c0cSGleb Kurtsouclass VarArgs(AnonymousDef):
336a1897c0cSGleb Kurtsou    def _pp(self, pp):
337a1897c0cSGleb Kurtsou        return "..."
338a1897c0cSGleb Kurtsou
339a1897c0cSGleb Kurtsouclass PointerDef(AnonymousDef):
340a1897c0cSGleb Kurtsou    def _pp(self, pp):
341a1897c0cSGleb Kurtsou        t = pp.run(self.type)
342a1897c0cSGleb Kurtsou        return "%s*" % (t,)
343a1897c0cSGleb Kurtsou
344a1897c0cSGleb Kurtsouclass BaseTypeDef(Def):
345a1897c0cSGleb Kurtsou    inttypes = ['DW_ATE_signed', 'DW_ATE_unsigned', 'DW_ATE_unsigned_char']
346a1897c0cSGleb Kurtsou    def _pp(self, pp):
347a1897c0cSGleb Kurtsou        if self.encoding in self.inttypes:
348a1897c0cSGleb Kurtsou            sign = '' if self.encoding == 'DW_ATE_signed' else 'u'
349c5f8185bSGleb Kurtsou            bits = int(self.byte_size, 0) * 8
350a1897c0cSGleb Kurtsou            return '%sint%s_t' % (sign, bits)
351c5f8185bSGleb Kurtsou        elif self.encoding == 'DW_ATE_signed_char' and int(self.byte_size, 0) == 1:
352a1897c0cSGleb Kurtsou            return 'char';
353c5f8185bSGleb Kurtsou        elif self.encoding == 'DW_ATE_boolean' and int(self.byte_size, 0) == 1:
354c5f8185bSGleb Kurtsou            return 'bool';
355a1897c0cSGleb Kurtsou        elif self.encoding == 'DW_ATE_float':
356c5f8185bSGleb Kurtsou            return self._mapval(int(self.byte_size, 0), {
357c5f8185bSGleb Kurtsou                16: 'long double',
358c5f8185bSGleb Kurtsou                8: 'double',
359c5f8185bSGleb Kurtsou                4: 'float',
360a1897c0cSGleb Kurtsou            })
361a1897c0cSGleb Kurtsou        raise NotImplementedError('Invalid encoding: %s' % self)
362a1897c0cSGleb Kurtsou
363a1897c0cSGleb Kurtsouclass TypeAliasDef(Def):
364a1897c0cSGleb Kurtsou    _is_alias = True
365a1897c0cSGleb Kurtsou    def _pp(self, pp):
366a1897c0cSGleb Kurtsou        alias = self._alias()
367a1897c0cSGleb Kurtsou        # push typedef name
368a1897c0cSGleb Kurtsou        if self.name and not alias.name:
369a1897c0cSGleb Kurtsou            alias.name = 'T(%s)' % self.name
370a1897c0cSGleb Kurtsou        # return type with modifiers
371a1897c0cSGleb Kurtsou        return self.type._pp(pp)
372a1897c0cSGleb Kurtsou
373a1897c0cSGleb Kurtsouclass EnumerationTypeDef(Def):
374a1897c0cSGleb Kurtsou    def _pp(self, pp):
375a1897c0cSGleb Kurtsou        return 'enum ' + self._name_opt('UNKNOWN')
376a1897c0cSGleb Kurtsou
377a1897c0cSGleb Kurtsouclass ConstTypeDef(AnonymousDef):
378a1897c0cSGleb Kurtsou    _is_alias = True
379a1897c0cSGleb Kurtsou    def _pp(self, pp):
380a1897c0cSGleb Kurtsou        return 'const ' + self.type._pp(pp)
381a1897c0cSGleb Kurtsou
382a1897c0cSGleb Kurtsouclass VolatileTypeDef(AnonymousDef):
383a1897c0cSGleb Kurtsou    _is_alias = True
384a1897c0cSGleb Kurtsou    def _pp(self, pp):
385a1897c0cSGleb Kurtsou        return 'volatile ' + self.type._pp(pp)
386a1897c0cSGleb Kurtsou
387c5f8185bSGleb Kurtsouclass RestrictTypeDef(AnonymousDef):
388c5f8185bSGleb Kurtsou    _is_alias = True
389c5f8185bSGleb Kurtsou    def _pp(self, pp):
390c5f8185bSGleb Kurtsou        return 'restrict ' + self.type._pp(pp)
391c5f8185bSGleb Kurtsou
392a1897c0cSGleb Kurtsouclass ArrayDef(AnonymousDef):
393a1897c0cSGleb Kurtsou    def _pp(self, pp):
394a1897c0cSGleb Kurtsou        t = pp.run(self.type)
395a1897c0cSGleb Kurtsou        assert len(self.subranges) == 1
396a1897c0cSGleb Kurtsou        try:
397a1897c0cSGleb Kurtsou            sz = int(self.subranges[0].upper_bound) + 1
398a1897c0cSGleb Kurtsou        except ValueError:
399a1897c0cSGleb Kurtsou            s = re.sub(r'\(.+\)', '', self.subranges[0].upper_bound)
400a1897c0cSGleb Kurtsou            sz = int(s) + 1
401a1897c0cSGleb Kurtsou        return '%s[%s]' % (t, sz)
402a1897c0cSGleb Kurtsou
403a1897c0cSGleb Kurtsouclass ArraySubrangeDef(AnonymousDef):
404a1897c0cSGleb Kurtsou    pass
405a1897c0cSGleb Kurtsou
406a1897c0cSGleb Kurtsouclass FunctionDef(Def):
407a1897c0cSGleb Kurtsou    def _pp(self, pp):
408a1897c0cSGleb Kurtsou        result = pp.run(self.result)
409a1897c0cSGleb Kurtsou        if not self.params:
410a1897c0cSGleb Kurtsou            params = "void"
411a1897c0cSGleb Kurtsou        else:
412a1897c0cSGleb Kurtsou            params = ', '.join([ pp.run(x) for x in self.params ])
413a1897c0cSGleb Kurtsou        return "%s %s(%s);" % (result, self.name, params)
414a1897c0cSGleb Kurtsou
415a1897c0cSGleb Kurtsouclass FunctionTypeDef(Def):
416a1897c0cSGleb Kurtsou    def _pp(self, pp):
417a1897c0cSGleb Kurtsou        result = pp.run(self.result)
418a1897c0cSGleb Kurtsou        if not self.params:
419a1897c0cSGleb Kurtsou            params = "void"
420a1897c0cSGleb Kurtsou        else:
421a1897c0cSGleb Kurtsou            params = ', '.join([ pp.run(x) for x in self.params ])
422a1897c0cSGleb Kurtsou        return "F(%s, %s, (%s))" % (self._name_opt(), result, params)
423a1897c0cSGleb Kurtsou
424a1897c0cSGleb Kurtsouclass ParameterDef(Def):
425a1897c0cSGleb Kurtsou    def _pp(self, pp):
426a1897c0cSGleb Kurtsou        t = pp.run(self.type)
427a1897c0cSGleb Kurtsou        return "%s %s" % (t, self._name_opt())
428a1897c0cSGleb Kurtsou
429c5f8185bSGleb Kurtsouclass VariableDef(Def):
430c5f8185bSGleb Kurtsou    def _pp(self, pp):
431c5f8185bSGleb Kurtsou        t = pp.run(self.type)
432c5f8185bSGleb Kurtsou        return "%s %s" % (t, self._name_opt())
433c5f8185bSGleb Kurtsou
434a1897c0cSGleb Kurtsou# TODO
435a1897c0cSGleb Kurtsouclass StructForwardDef(Def):
436a1897c0cSGleb Kurtsou    pass
437a1897c0cSGleb Kurtsou
438a1897c0cSGleb Kurtsouclass IncompleteDef(Def):
439a1897c0cSGleb Kurtsou    def update(self, complete, cache=None):
440a1897c0cSGleb Kurtsou        self.complete = complete
441a1897c0cSGleb Kurtsou        complete.incomplete = self
442a1897c0cSGleb Kurtsou        if cache != None:
443a1897c0cSGleb Kurtsou            cached = cache.get(self.id)
444a1897c0cSGleb Kurtsou            if cached != None and isinstance(cached, IncompleteDef):
445a1897c0cSGleb Kurtsou                cache.replace(self.id, complete)
446a1897c0cSGleb Kurtsou
447a1897c0cSGleb Kurtsouclass StructIncompleteDef(IncompleteDef):
448a1897c0cSGleb Kurtsou    def _pp(self, pp):
449a1897c0cSGleb Kurtsou        return "struct %s" % (self.name,)
450a1897c0cSGleb Kurtsou
451a1897c0cSGleb Kurtsouclass UnionIncompleteDef(IncompleteDef):
452a1897c0cSGleb Kurtsou    def _pp(self, pp):
453a1897c0cSGleb Kurtsou        return "union %s" % (self.name,)
454a1897c0cSGleb Kurtsou
455a1897c0cSGleb Kurtsouclass StructDef(Def):
456a1897c0cSGleb Kurtsou    def _pp_ex(self, pp, suffix=';'):
457a1897c0cSGleb Kurtsou        members = [ pp.run(x) for x in self.members ]
458a1897c0cSGleb Kurtsou        return "struct %s { %s }%s" % \
459a1897c0cSGleb Kurtsou                (self._name_opt(), ' '.join(members), suffix)
460a1897c0cSGleb Kurtsou    def _pp(self, pp):
461a1897c0cSGleb Kurtsou        if self.name:
462a1897c0cSGleb Kurtsou            pp.run_nested(self)
463a1897c0cSGleb Kurtsou            return "struct %s" % (self.name,)
464a1897c0cSGleb Kurtsou        else:
465a1897c0cSGleb Kurtsou            return self._pp_ex(pp, suffix='')
466a1897c0cSGleb Kurtsou
467a1897c0cSGleb Kurtsouclass UnionDef(Def):
468a1897c0cSGleb Kurtsou    def _pp_ex(self, pp, suffix=';'):
469a1897c0cSGleb Kurtsou        members = [ pp.run(x) for x in self.members ]
470a1897c0cSGleb Kurtsou        return "union %s { %s }%s" % \
471a1897c0cSGleb Kurtsou                (self._name_opt(), ' '.join(members), suffix)
472a1897c0cSGleb Kurtsou    def _pp(self, pp):
473a1897c0cSGleb Kurtsou        if self.name:
474a1897c0cSGleb Kurtsou            pp.run_nested(self)
475a1897c0cSGleb Kurtsou            return "union %s" % (self.name,)
476a1897c0cSGleb Kurtsou        else:
477a1897c0cSGleb Kurtsou            return self._pp_ex(pp, suffix='')
478a1897c0cSGleb Kurtsou
479a1897c0cSGleb Kurtsouclass MemberDef(Def):
480a1897c0cSGleb Kurtsou    def _pp(self, pp):
481a1897c0cSGleb Kurtsou        t = pp.run(self.type)
482a1897c0cSGleb Kurtsou        if self.bit_size:
483a1897c0cSGleb Kurtsou            bits = ":%s" % self.bit_size
484a1897c0cSGleb Kurtsou        else:
485a1897c0cSGleb Kurtsou            bits = ""
486a1897c0cSGleb Kurtsou        return "%s %s%s;" % (t, self._name_opt(), bits)
487a1897c0cSGleb Kurtsou
488a1897c0cSGleb Kurtsouclass Dwarf(object):
489a1897c0cSGleb Kurtsou
490a1897c0cSGleb Kurtsou    cmpcache = Cache(enabled=Config.cmpcache_enabled)
491a1897c0cSGleb Kurtsou
492a1897c0cSGleb Kurtsou    def __init__(self, dump):
493a1897c0cSGleb Kurtsou        self.dump = dump
494a1897c0cSGleb Kurtsou
495a1897c0cSGleb Kurtsou    def _build_optarg_type(self, praw):
496a1897c0cSGleb Kurtsou        type = praw.optarg('type', Void())
497a1897c0cSGleb Kurtsou        if type != Void():
498a1897c0cSGleb Kurtsou            type = self.buildref(praw.unit, type)
499a1897c0cSGleb Kurtsou        return type
500a1897c0cSGleb Kurtsou
501a1897c0cSGleb Kurtsou    def build_subprogram(self, raw):
502a1897c0cSGleb Kurtsou        if raw.optname == None:
503a1897c0cSGleb Kurtsou            raw.setname('SUBPROGRAM_NONAME_' + raw.arg('low_pc'));
504a1897c0cSGleb Kurtsou        params = [ self.build(x) for x in raw.nested ]
505a1897c0cSGleb Kurtsou        result = self._build_optarg_type(raw)
506a1897c0cSGleb Kurtsou        return FunctionDef(raw.id, raw.name, params=params, result=result)
507a1897c0cSGleb Kurtsou
508c5f8185bSGleb Kurtsou    def build_variable(self, raw):
509c5f8185bSGleb Kurtsou        type = self._build_optarg_type(raw)
510c5f8185bSGleb Kurtsou        return VariableDef(raw.id, raw.optname, type=type)
511c5f8185bSGleb Kurtsou
512a1897c0cSGleb Kurtsou    def build_subroutine_type(self, raw):
513a1897c0cSGleb Kurtsou        params = [ self.build(x) for x in raw.nested ]
514a1897c0cSGleb Kurtsou        result = self._build_optarg_type(raw)
515a1897c0cSGleb Kurtsou        return FunctionTypeDef(raw.id, raw.optname, params=params, result=result)
516a1897c0cSGleb Kurtsou
517a1897c0cSGleb Kurtsou    def build_formal_parameter(self, raw):
518a1897c0cSGleb Kurtsou        type = self._build_optarg_type(raw)
519a1897c0cSGleb Kurtsou        return ParameterDef(raw.id, raw.optname, type=type)
520a1897c0cSGleb Kurtsou
521a1897c0cSGleb Kurtsou    def build_pointer_type(self, raw):
522a1897c0cSGleb Kurtsou        type = self._build_optarg_type(raw)
523a1897c0cSGleb Kurtsou        return PointerDef(raw.id, type=type)
524a1897c0cSGleb Kurtsou
525a1897c0cSGleb Kurtsou    def build_member(self, raw):
526a1897c0cSGleb Kurtsou        type = self.buildref(raw.unit, raw.arg('type'))
527a1897c0cSGleb Kurtsou        return MemberDef(raw.id, raw.name, type=type,
528a1897c0cSGleb Kurtsou                bit_size=raw.optarg('bit_size', None))
529a1897c0cSGleb Kurtsou
530a1897c0cSGleb Kurtsou    def build_structure_type(self, raw):
531a1897c0cSGleb Kurtsou        incomplete = raw.unit.incomplete.get(raw.id)
532a1897c0cSGleb Kurtsou        if incomplete == None:
533a1897c0cSGleb Kurtsou            incomplete = StructIncompleteDef(raw.id, raw.optname)
534a1897c0cSGleb Kurtsou            raw.unit.incomplete.put(raw.id, incomplete)
535a1897c0cSGleb Kurtsou        else:
536a1897c0cSGleb Kurtsou            return incomplete
537a1897c0cSGleb Kurtsou        members = [ self.build(x) for x in raw.nested ]
538a1897c0cSGleb Kurtsou        byte_size = raw.optarg('byte_size', None)
539a1897c0cSGleb Kurtsou        if byte_size == None:
540a1897c0cSGleb Kurtsou            obj = StructForwardDef(raw.id, raw.name, members=members,
541a1897c0cSGleb Kurtsou                    forcename=raw.name)
542a1897c0cSGleb Kurtsou        obj = StructDef(raw.id, raw.optname, members=members,
543a1897c0cSGleb Kurtsou                byte_size=byte_size)
544a1897c0cSGleb Kurtsou        incomplete.update(obj, cache=raw.unit.cache)
545a1897c0cSGleb Kurtsou        return obj
546a1897c0cSGleb Kurtsou
547a1897c0cSGleb Kurtsou    def build_union_type(self, raw):
548a1897c0cSGleb Kurtsou        incomplete = raw.unit.incomplete.get(raw.id)
549a1897c0cSGleb Kurtsou        if incomplete == None:
550a1897c0cSGleb Kurtsou            incomplete = UnionIncompleteDef(raw.id, raw.optname)
551a1897c0cSGleb Kurtsou            raw.unit.incomplete.put(raw.id, incomplete)
552a1897c0cSGleb Kurtsou        else:
553a1897c0cSGleb Kurtsou            return incomplete
554a1897c0cSGleb Kurtsou        members = [ self.build(x) for x in raw.nested ]
555a1897c0cSGleb Kurtsou        byte_size = raw.optarg('byte_size', None)
556a1897c0cSGleb Kurtsou        obj = UnionDef(raw.id, raw.optname, members=members,
557a1897c0cSGleb Kurtsou                byte_size=byte_size)
558a1897c0cSGleb Kurtsou        obj.incomplete = incomplete
559a1897c0cSGleb Kurtsou        incomplete.complete = obj
560a1897c0cSGleb Kurtsou        return obj
561a1897c0cSGleb Kurtsou
562a1897c0cSGleb Kurtsou    def build_typedef(self, raw):
563a1897c0cSGleb Kurtsou        type = self._build_optarg_type(raw)
564a1897c0cSGleb Kurtsou        return TypeAliasDef(raw.id, raw.name, type=type)
565a1897c0cSGleb Kurtsou
566a1897c0cSGleb Kurtsou    def build_const_type(self, raw):
567a1897c0cSGleb Kurtsou        type = self._build_optarg_type(raw)
568a1897c0cSGleb Kurtsou        return ConstTypeDef(raw.id, type=type)
569a1897c0cSGleb Kurtsou
570a1897c0cSGleb Kurtsou    def build_volatile_type(self, raw):
571a1897c0cSGleb Kurtsou        type = self._build_optarg_type(raw)
572a1897c0cSGleb Kurtsou        return VolatileTypeDef(raw.id, type=type)
573a1897c0cSGleb Kurtsou
574c5f8185bSGleb Kurtsou    def build_restrict_type(self, raw):
575c5f8185bSGleb Kurtsou        type = self._build_optarg_type(raw)
576c5f8185bSGleb Kurtsou        return RestrictTypeDef(raw.id, type=type)
577c5f8185bSGleb Kurtsou
578a1897c0cSGleb Kurtsou    def build_enumeration_type(self, raw):
579a1897c0cSGleb Kurtsou        # TODO handle DW_TAG_enumerator ???
580a1897c0cSGleb Kurtsou        return EnumerationTypeDef(raw.id, name=raw.optname,
581a1897c0cSGleb Kurtsou                byte_size=raw.arg('byte_size'))
582a1897c0cSGleb Kurtsou
583a1897c0cSGleb Kurtsou    def build_base_type(self, raw):
584a1897c0cSGleb Kurtsou        return BaseTypeDef(raw.id, raw.optname,
585a1897c0cSGleb Kurtsou                byte_size=raw.arg('byte_size'), encoding=raw.arg('encoding'))
586a1897c0cSGleb Kurtsou
587a1897c0cSGleb Kurtsou    def build_array_type(self, raw):
588a1897c0cSGleb Kurtsou        type = self.buildref(raw.unit, raw.arg('type'))
589a1897c0cSGleb Kurtsou        subranges = [ self.build(x) for x in raw.nested ]
590a1897c0cSGleb Kurtsou        return ArrayDef(raw.id, type=type, subranges=subranges)
591a1897c0cSGleb Kurtsou
592a1897c0cSGleb Kurtsou    def build_subrange_type(self, raw):
593a1897c0cSGleb Kurtsou        type = self.buildref(raw.unit, raw.arg('type'))
594a1897c0cSGleb Kurtsou        return ArraySubrangeDef(raw.id, type=type,
595a1897c0cSGleb Kurtsou                upper_bound=raw.optarg('upper_bound', 0))
596a1897c0cSGleb Kurtsou
597a1897c0cSGleb Kurtsou    def build_unspecified_parameters(self, raw):
598a1897c0cSGleb Kurtsou        return VarArgs(raw.id)
599a1897c0cSGleb Kurtsou
600a1897c0cSGleb Kurtsou    def _get_id(self, id):
601a1897c0cSGleb Kurtsou        try:
602a1897c0cSGleb Kurtsou            return int(id)
603a1897c0cSGleb Kurtsou        except ValueError:
604a1897c0cSGleb Kurtsou            if (id.startswith('<') and id.endswith('>')):
605c5f8185bSGleb Kurtsou                return int(id[1:-1], 0)
606a1897c0cSGleb Kurtsou            else:
607a1897c0cSGleb Kurtsou                raise ValueError("Invalid dwarf id: %s" % id)
608a1897c0cSGleb Kurtsou
609a1897c0cSGleb Kurtsou    def build(self, raw):
610a1897c0cSGleb Kurtsou        obj = raw.unit.cache.get(raw.id)
611a1897c0cSGleb Kurtsou        if obj != None:
612a1897c0cSGleb Kurtsou            return obj
613a1897c0cSGleb Kurtsou        builder_name = raw.tag.replace('DW_TAG_', 'build_')
614a1897c0cSGleb Kurtsou        try:
615a1897c0cSGleb Kurtsou            builder = getattr(self, builder_name)
616a1897c0cSGleb Kurtsou        except AttributeError:
617a1897c0cSGleb Kurtsou            raise AttributeError("Unknown dwarf tag: %s" % raw)
618a1897c0cSGleb Kurtsou        obj = builder(raw)
619a1897c0cSGleb Kurtsou        raw.unit.cache.put(obj.id, obj)
620a1897c0cSGleb Kurtsou        return obj
621a1897c0cSGleb Kurtsou
622a1897c0cSGleb Kurtsou    def buildref(self, unit, id):
623a1897c0cSGleb Kurtsou        id = self._get_id(id)
624a1897c0cSGleb Kurtsou        raw = unit.tags[id]
625a1897c0cSGleb Kurtsou        obj = self.build(raw)
626a1897c0cSGleb Kurtsou        return obj
627a1897c0cSGleb Kurtsou
628a1897c0cSGleb Kurtsou# }}}
629a1897c0cSGleb Kurtsou
630a1897c0cSGleb Kurtsouclass Shlib(object):
631a1897c0cSGleb Kurtsou    def __init__(self, libfile):
632a1897c0cSGleb Kurtsou        self.libfile = libfile
633a1897c0cSGleb Kurtsou        self.versions = {}
634a1897c0cSGleb Kurtsou        self.alias_syms = {}
635a1897c0cSGleb Kurtsou
636a1897c0cSGleb Kurtsou    def parse_objdump(self):
637a1897c0cSGleb Kurtsou        objdump = ObjdumpParser(self.libfile)
638a1897c0cSGleb Kurtsou        objdump.run()
639a1897c0cSGleb Kurtsou        for p in objdump.dynamic_symbols:
640a1897c0cSGleb Kurtsou            vername = p['ver']
641a1897c0cSGleb Kurtsou            if vername.startswith('(') and vername.endswith(')'):
642a1897c0cSGleb Kurtsou                vername = vername[1:-1]
643a1897c0cSGleb Kurtsou            if not Config.version_filter.match(vername):
644a1897c0cSGleb Kurtsou                continue
645a1897c0cSGleb Kurtsou            if not Config.symbol_filter.match(p['symbol']):
646a1897c0cSGleb Kurtsou                continue
647a1897c0cSGleb Kurtsou            sym = Symbol(p['symbol'], p['offset'], vername, self)
648aef675d8SCraig Rodrigues            if vername not in self.versions:
649a1897c0cSGleb Kurtsou                self.versions[vername] = VersionMap(vername)
650a1897c0cSGleb Kurtsou            self.versions[vername].append(sym)
651a1897c0cSGleb Kurtsou        if Config.alias_prefixes:
652a1897c0cSGleb Kurtsou            self.local_offsetmap = objdump.local_offsetmap
653a1897c0cSGleb Kurtsou            for p in objdump.local_symbols:
654a1897c0cSGleb Kurtsou                for prefix in Config.alias_prefixes:
655a1897c0cSGleb Kurtsou                    if not p['symbol'].startswith(prefix):
656a1897c0cSGleb Kurtsou                        continue
657a1897c0cSGleb Kurtsou                    alias = SymbolAlias(p['symbol'], prefix, p['offset'])
658aef675d8SCraig Rodrigues                    if alias.name in self.alias_syms:
659a1897c0cSGleb Kurtsou                        prevalias = self.alias_syms[alias.name]
660a1897c0cSGleb Kurtsou                        if alias.name != prevalias.name or \
661a1897c0cSGleb Kurtsou                                alias.offset != prevalias.offset:
662a1897c0cSGleb Kurtsou                            warn(Config.w_alias, "Symbol alias is " \
663a1897c0cSGleb Kurtsou                                    "already defined: %s: %s at %08x -- %s at %08x" % \
664a1897c0cSGleb Kurtsou                                    (alias.alias, alias.name,  alias.offset,
665a1897c0cSGleb Kurtsou                                            prevalias.name, prevalias.offset))
666a1897c0cSGleb Kurtsou                    self.alias_syms[alias.name] = alias
667a1897c0cSGleb Kurtsou
668a1897c0cSGleb Kurtsou    def parse_dwarfdump(self):
669a1897c0cSGleb Kurtsou        dwarfdump = DwarfdumpParser(self.libfile)
670a1897c0cSGleb Kurtsou        def lookup(sym):
671a1897c0cSGleb Kurtsou            raw = None
672a1897c0cSGleb Kurtsou            try:
673a1897c0cSGleb Kurtsou                raw = dwarfdump.offsetmap[sym.offset]
674a1897c0cSGleb Kurtsou            except:
675a1897c0cSGleb Kurtsou                try:
676a1897c0cSGleb Kurtsou                    localnames = self.local_offsetmap[sym.offset]
677a1897c0cSGleb Kurtsou                    localnames.sort(key=lambda x: -len(x))
678a1897c0cSGleb Kurtsou                    for localname in localnames:
679aef675d8SCraig Rodrigues                        if localname not in self.alias_syms:
680a1897c0cSGleb Kurtsou                            continue
681a1897c0cSGleb Kurtsou                        alias = self.alias_syms[localname]
682a1897c0cSGleb Kurtsou                        raw = dwarfdump.offsetmap[alias.offset]
683a1897c0cSGleb Kurtsou                        break
684a1897c0cSGleb Kurtsou                except:
685a1897c0cSGleb Kurtsou                    pass
686a1897c0cSGleb Kurtsou            return raw
687a1897c0cSGleb Kurtsou        dwarfdump.run()
688a1897c0cSGleb Kurtsou        dwarf = Dwarf(dwarfdump)
689a1897c0cSGleb Kurtsou        for ver in self.versions.values():
690a1897c0cSGleb Kurtsou            for sym in ver.symbols.values():
691a1897c0cSGleb Kurtsou                raw = lookup(sym);
692a1897c0cSGleb Kurtsou                if not raw:
693a1897c0cSGleb Kurtsou                    warn(Config.w_symbol, "Symbol %s (%s) not found at offset 0x%x" % \
694a1897c0cSGleb Kurtsou                            (sym.name_ver, self.libfile, sym.offset))
695a1897c0cSGleb Kurtsou                    continue
696a1897c0cSGleb Kurtsou                if Config.verbose >= 3:
697749f65e3SCraig Rodrigues                    print("Parsing symbol %s (%s)" % (sym.name_ver, self.libfile))
698a1897c0cSGleb Kurtsou                sym.definition = dwarf.build(raw)
699a1897c0cSGleb Kurtsou
700a1897c0cSGleb Kurtsou    def parse(self):
701a1897c0cSGleb Kurtsou        if not os.path.isfile(self.libfile):
702749f65e3SCraig Rodrigues            print("No such file: %s" % self.libfile, file=sys.stderr)
703a1897c0cSGleb Kurtsou            sys.exit(1)
704a1897c0cSGleb Kurtsou        self.parse_objdump()
705a1897c0cSGleb Kurtsou        self.parse_dwarfdump()
706a1897c0cSGleb Kurtsou
707a1897c0cSGleb Kurtsou# {{{ parsers
708a1897c0cSGleb Kurtsou
709a1897c0cSGleb Kurtsouclass Parser(object):
710a1897c0cSGleb Kurtsou    def __init__(self, proc):
711a1897c0cSGleb Kurtsou        self.proc = proc
712a1897c0cSGleb Kurtsou        self.parser = self.parse_begin
713a1897c0cSGleb Kurtsou
714a1897c0cSGleb Kurtsou    def run(self):
715a1897c0cSGleb Kurtsou        fd = os.popen(self.proc, 'r')
716a1897c0cSGleb Kurtsou        while True:
717a1897c0cSGleb Kurtsou            line = fd.readline()
718a1897c0cSGleb Kurtsou            if (not line):
719a1897c0cSGleb Kurtsou                break
720a1897c0cSGleb Kurtsou            line = line.strip()
721a1897c0cSGleb Kurtsou            if (line):
722a1897c0cSGleb Kurtsou                self.parser(line)
723a1897c0cSGleb Kurtsou        err = fd.close()
724a1897c0cSGleb Kurtsou        if err:
725749f65e3SCraig Rodrigues            print("Execution failed: %s" % self.proc, file=sys.stderr)
726a1897c0cSGleb Kurtsou            sys.exit(2)
727a1897c0cSGleb Kurtsou
728a1897c0cSGleb Kurtsou    def parse_begin(self, line):
729a1897c0cSGleb Kurtsou        print(line)
730a1897c0cSGleb Kurtsou
731a1897c0cSGleb Kurtsouclass ObjdumpParser(Parser):
732a1897c0cSGleb Kurtsou
733a1897c0cSGleb Kurtsou    re_header = re.compile('(?P<table>\w*)\s*SYMBOL TABLE:')
734a1897c0cSGleb Kurtsou
735a1897c0cSGleb Kurtsou    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]*)')
736a1897c0cSGleb Kurtsou    re_lame_symbol = re.compile('(?P<offset>[0-9a-fA-F]+)\s+(?P<bind>\w+)\s+\*[A-Z]+\*')
737a1897c0cSGleb Kurtsou
738a1897c0cSGleb Kurtsou    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]*)')
739a1897c0cSGleb Kurtsou
740a1897c0cSGleb Kurtsou    def __init__(self, libfile):
741a1897c0cSGleb Kurtsou        Parser.__init__(self, "%s -wtT %s" % (Config.objdump, libfile))
742a1897c0cSGleb Kurtsou        self.dynamic_symbols = []
743a1897c0cSGleb Kurtsou        self.local_symbols = []
744a1897c0cSGleb Kurtsou        self.local_offsetmap = {}
745a1897c0cSGleb Kurtsou
746a1897c0cSGleb Kurtsou    def parse_begin(self, line):
747a1897c0cSGleb Kurtsou        self.parse_header(line)
748a1897c0cSGleb Kurtsou
749a1897c0cSGleb Kurtsou    def add_symbol(self, table, symbol, offsetmap = None):
750a1897c0cSGleb Kurtsou        offset = int(symbol['offset'], 16);
751a1897c0cSGleb Kurtsou        symbol['offset'] = offset
752a1897c0cSGleb Kurtsou        if (offset == 0):
753a1897c0cSGleb Kurtsou            return
754a1897c0cSGleb Kurtsou        table.append(symbol)
755a1897c0cSGleb Kurtsou        if offsetmap != None:
756aef675d8SCraig Rodrigues            if offset not in offsetmap:
757a1897c0cSGleb Kurtsou                offsetmap[offset] = [symbol['symbol']]
758a1897c0cSGleb Kurtsou            else:
759a1897c0cSGleb Kurtsou                offsetmap[offset].append(symbol['symbol'])
760a1897c0cSGleb Kurtsou
761a1897c0cSGleb Kurtsou    def parse_header(self, line):
762a1897c0cSGleb Kurtsou        m = self.re_header.match(line)
763a1897c0cSGleb Kurtsou        if (m):
764a1897c0cSGleb Kurtsou            table = m.group('table')
765a1897c0cSGleb Kurtsou            if (table == "DYNAMIC"):
766a1897c0cSGleb Kurtsou                self.parser = self.parse_dynamic
767a1897c0cSGleb Kurtsou            elif table == '':
768a1897c0cSGleb Kurtsou                self.parser = self.parse_local
769a1897c0cSGleb Kurtsou            else:
770a1897c0cSGleb Kurtsou                raise ValueError("Invalid symbol table: %s" % table)
771a1897c0cSGleb Kurtsou            return True
772a1897c0cSGleb Kurtsou        return False
773a1897c0cSGleb Kurtsou
774a1897c0cSGleb Kurtsou    def parse_local(self, line):
775a1897c0cSGleb Kurtsou        if (self.parse_header(line)):
776a1897c0cSGleb Kurtsou            return
777a1897c0cSGleb Kurtsou        if (self.re_lame_symbol.match(line)):
778a1897c0cSGleb Kurtsou            return
779a1897c0cSGleb Kurtsou        m = self.re_local_symbol.match(line)
780a1897c0cSGleb Kurtsou        if (not m):
781a1897c0cSGleb Kurtsou            return
782a1897c0cSGleb Kurtsou            #raise ValueError("Invalid symbol definition: %s" % line)
783a1897c0cSGleb Kurtsou        p = m.groupdict()
784a1897c0cSGleb Kurtsou        if (p['symbol'] and p['symbol'].find('@') == -1):
785a1897c0cSGleb Kurtsou            self.add_symbol(self.local_symbols, p, self.local_offsetmap);
786a1897c0cSGleb Kurtsou
787a1897c0cSGleb Kurtsou    def parse_dynamic(self, line):
788a1897c0cSGleb Kurtsou        if (self.parse_header(line)):
789a1897c0cSGleb Kurtsou            return
790a1897c0cSGleb Kurtsou        if (self.re_lame_symbol.match(line)):
791a1897c0cSGleb Kurtsou            return
792a1897c0cSGleb Kurtsou        m = self.re_dynamic_symbol.match(line)
793a1897c0cSGleb Kurtsou        if (not m):
794a1897c0cSGleb Kurtsou            raise ValueError("Invalid symbol definition: %s" % line)
795a1897c0cSGleb Kurtsou        p = m.groupdict()
796a1897c0cSGleb Kurtsou        if (p['symbol'] and p['ver']):
797a1897c0cSGleb Kurtsou            self.add_symbol(self.dynamic_symbols, p);
798a1897c0cSGleb Kurtsou
799a1897c0cSGleb Kurtsouclass DwarfdumpParser(Parser):
800a1897c0cSGleb Kurtsou
801a1897c0cSGleb Kurtsou    tagcache_stats = Cache.CacheStats()
802a1897c0cSGleb Kurtsou
803a1897c0cSGleb Kurtsou    class Unit(object):
804a1897c0cSGleb Kurtsou        def __init__(self):
805a1897c0cSGleb Kurtsou            self.cache = Cache(enabled=Config.dwarfcache_enabled,
806a1897c0cSGleb Kurtsou                    stats=DwarfdumpParser.tagcache_stats)
807a1897c0cSGleb Kurtsou            self.incomplete = Cache()
808a1897c0cSGleb Kurtsou            self.tags = {}
809a1897c0cSGleb Kurtsou
810a1897c0cSGleb Kurtsou    class Tag(object):
811a1897c0cSGleb Kurtsou        def __init__(self, unit, data):
812a1897c0cSGleb Kurtsou            self.unit = unit
813c5f8185bSGleb Kurtsou            self.id = int(data['id'], 0)
814a1897c0cSGleb Kurtsou            self.level = int(data['level'])
815a1897c0cSGleb Kurtsou            self.tag = data['tag']
816a1897c0cSGleb Kurtsou            self.args = {}
817a1897c0cSGleb Kurtsou            self.nested = []
818a1897c0cSGleb Kurtsou
819a1897c0cSGleb Kurtsou        @property
820a1897c0cSGleb Kurtsou        def name(self):
821a1897c0cSGleb Kurtsou            return self.arg('name')
822a1897c0cSGleb Kurtsou
823a1897c0cSGleb Kurtsou        @property
824a1897c0cSGleb Kurtsou        def optname(self):
825a1897c0cSGleb Kurtsou            return self.optarg('name', None)
826a1897c0cSGleb Kurtsou
827a1897c0cSGleb Kurtsou        def setname(self, name):
828a1897c0cSGleb Kurtsou            self.args['DW_AT_name'] = name
829a1897c0cSGleb Kurtsou
830a1897c0cSGleb Kurtsou        def arg(self, a):
831a1897c0cSGleb Kurtsou            name = 'DW_AT_' + a
832a1897c0cSGleb Kurtsou            try:
833a1897c0cSGleb Kurtsou                return self.args[name]
834a1897c0cSGleb Kurtsou            except KeyError:
835a1897c0cSGleb Kurtsou                raise KeyError("Argument '%s' not found in %s: %s" %
836a1897c0cSGleb Kurtsou                        (name, self, self.args))
837a1897c0cSGleb Kurtsou
838a1897c0cSGleb Kurtsou        def optarg(self, a, default):
839a1897c0cSGleb Kurtsou            try:
840a1897c0cSGleb Kurtsou                return self.arg(a)
841a1897c0cSGleb Kurtsou            except KeyError:
842a1897c0cSGleb Kurtsou                return default
843a1897c0cSGleb Kurtsou
844a1897c0cSGleb Kurtsou        def __repr__(self):
845a1897c0cSGleb Kurtsou            return "Tag(%d, %d, %s)" % (self.level, self.id, self.tag)
846a1897c0cSGleb Kurtsou
847c5f8185bSGleb Kurtsou    re_header = re.compile('<(?P<level>\d+)><(?P<id>[0xX0-9a-fA-F]+(?:\+(0[xX])?[0-9a-fA-F]+)?)><(?P<tag>\w+)>')
848a1897c0cSGleb Kurtsou    re_argname = re.compile('(?P<arg>\w+)<')
849a1897c0cSGleb Kurtsou    re_argunknown = re.compile('<Unknown AT value \w+><[^<>]+>')
850a1897c0cSGleb Kurtsou
851a1897c0cSGleb Kurtsou    skip_tags = set([
852a1897c0cSGleb Kurtsou        'DW_TAG_lexical_block',
853a1897c0cSGleb Kurtsou        'DW_TAG_inlined_subroutine',
854a1897c0cSGleb Kurtsou        'DW_TAG_label',
855a1897c0cSGleb Kurtsou        'DW_TAG_variable',
856a1897c0cSGleb Kurtsou        ])
857a1897c0cSGleb Kurtsou
858c5f8185bSGleb Kurtsou    external_tags = set([
859c5f8185bSGleb Kurtsou        'DW_TAG_variable',
860c5f8185bSGleb Kurtsou        ])
861c5f8185bSGleb Kurtsou
862a1897c0cSGleb Kurtsou    def __init__(self, libfile):
863a1897c0cSGleb Kurtsou        Parser.__init__(self, "%s -di %s" % (Config.dwarfdump, libfile))
864a1897c0cSGleb Kurtsou        self.current_unit = None
865a1897c0cSGleb Kurtsou        self.offsetmap = {}
866a1897c0cSGleb Kurtsou        self.stack = []
867a1897c0cSGleb Kurtsou
868a1897c0cSGleb Kurtsou    def parse_begin(self, line):
869a1897c0cSGleb Kurtsou        if line == '.debug_info':
870a1897c0cSGleb Kurtsou            self.parser = self.parse_debuginfo
871a1897c0cSGleb Kurtsou        else:
872a1897c0cSGleb Kurtsou            raise ValueError("Invalid dwarfdump header: %s" % line)
873a1897c0cSGleb Kurtsou
874a1897c0cSGleb Kurtsou    def parse_argvalue(self, args):
875a1897c0cSGleb Kurtsou        assert args.startswith('<')
876a1897c0cSGleb Kurtsou        i = 1
877a1897c0cSGleb Kurtsou        cnt = 1
878a1897c0cSGleb Kurtsou        while i < len(args) and args[i]:
879a1897c0cSGleb Kurtsou            if args[i] == '<':
880a1897c0cSGleb Kurtsou                cnt += 1
881a1897c0cSGleb Kurtsou            elif args[i] == '>':
882a1897c0cSGleb Kurtsou                cnt -= 1
883a1897c0cSGleb Kurtsou                if cnt == 0:
884a1897c0cSGleb Kurtsou                    break
885a1897c0cSGleb Kurtsou            i = i + 1
886a1897c0cSGleb Kurtsou        value = args[1:i]
887a1897c0cSGleb Kurtsou        args = args[i+1:]
888a1897c0cSGleb Kurtsou        return (args, value)
889a1897c0cSGleb Kurtsou
890a1897c0cSGleb Kurtsou    def parse_arg(self, tag, args):
891a1897c0cSGleb Kurtsou        m = self.re_argname.match(args)
892a1897c0cSGleb Kurtsou        if not m:
893a1897c0cSGleb Kurtsou            m = self.re_argunknown.match(args)
894a1897c0cSGleb Kurtsou            if not m:
895a1897c0cSGleb Kurtsou                raise ValueError("Invalid dwarfdump: couldn't parse arguments: %s" %
896a1897c0cSGleb Kurtsou                        args)
897a1897c0cSGleb Kurtsou            args = args[len(m.group(0)):].lstrip()
898a1897c0cSGleb Kurtsou            return args
899a1897c0cSGleb Kurtsou        argname = m.group('arg')
900a1897c0cSGleb Kurtsou        args = args[len(argname):]
901a1897c0cSGleb Kurtsou        value = []
902a1897c0cSGleb Kurtsou        while len(args) > 0 and args.startswith('<'):
903a1897c0cSGleb Kurtsou            (args, v) = self.parse_argvalue(args)
904a1897c0cSGleb Kurtsou            value.append(v)
905a1897c0cSGleb Kurtsou        args = args.lstrip()
906a1897c0cSGleb Kurtsou        if len(value) == 1:
907a1897c0cSGleb Kurtsou            value = value[0]
908a1897c0cSGleb Kurtsou        tag.args[argname] = value
909a1897c0cSGleb Kurtsou        return args
910a1897c0cSGleb Kurtsou
911a1897c0cSGleb Kurtsou    def parse_debuginfo(self, line):
912a1897c0cSGleb Kurtsou        m = self.re_header.match(line)
913a1897c0cSGleb Kurtsou        if not m:
914a1897c0cSGleb Kurtsou            raise ValueError("Invalid dwarfdump: %s" % line)
915a1897c0cSGleb Kurtsou        if m.group('level') == '0':
916a1897c0cSGleb Kurtsou            self.current_unit = DwarfdumpParser.Unit()
917a1897c0cSGleb Kurtsou            return
918a1897c0cSGleb Kurtsou        tag = DwarfdumpParser.Tag(self.current_unit, m.groupdict())
919a1897c0cSGleb Kurtsou        args = line[len(m.group(0)):].lstrip()
920a1897c0cSGleb Kurtsou        while args:
921a1897c0cSGleb Kurtsou            args = self.parse_arg(tag, args)
922a1897c0cSGleb Kurtsou        tag.unit.tags[tag.id] = tag
923c5f8185bSGleb Kurtsou        def parse_offset(tag):
924aef675d8SCraig Rodrigues            if 'DW_AT_low_pc' in tag.args:
925c5f8185bSGleb Kurtsou                return int(tag.args['DW_AT_low_pc'], 16)
926aef675d8SCraig Rodrigues            elif 'DW_AT_location' in tag.args:
927c5f8185bSGleb Kurtsou                location = tag.args['DW_AT_location']
928c5f8185bSGleb Kurtsou                if location.startswith('DW_OP_addr'):
929c5f8185bSGleb Kurtsou                    return int(location.replace('DW_OP_addr', ''), 16)
930c5f8185bSGleb Kurtsou            return None
931c5f8185bSGleb Kurtsou        offset = parse_offset(tag)
932c5f8185bSGleb Kurtsou        if offset is not None and \
933c5f8185bSGleb Kurtsou                (tag.tag not in DwarfdumpParser.skip_tags or \
934aef675d8SCraig Rodrigues                ('DW_AT_external' in tag.args and \
935c5f8185bSGleb Kurtsou                tag.tag in DwarfdumpParser.external_tags)):
936aef675d8SCraig Rodrigues            if offset in self.offsetmap:
937a1897c0cSGleb Kurtsou                raise ValueError("Dwarf dump parse error: " +
938bd0ca238SPedro F. Giffuni                        "symbol is already defined at offset 0x%x" % offset)
939a1897c0cSGleb Kurtsou            self.offsetmap[offset] = tag
940a1897c0cSGleb Kurtsou        if len(self.stack) > 0:
941a1897c0cSGleb Kurtsou            prev = self.stack.pop()
942a1897c0cSGleb Kurtsou            while prev.level >= tag.level and len(self.stack) > 0:
943a1897c0cSGleb Kurtsou                prev = self.stack.pop()
944a1897c0cSGleb Kurtsou            if prev.level < tag.level:
945a1897c0cSGleb Kurtsou                assert prev.level == tag.level - 1
946a1897c0cSGleb Kurtsou                # TODO check DW_AT_sibling ???
947a1897c0cSGleb Kurtsou                if tag.tag not in DwarfdumpParser.skip_tags:
948a1897c0cSGleb Kurtsou                    prev.nested.append(tag)
949a1897c0cSGleb Kurtsou                self.stack.append(prev)
950a1897c0cSGleb Kurtsou        self.stack.append(tag)
951a1897c0cSGleb Kurtsou        assert len(self.stack) == tag.level
952a1897c0cSGleb Kurtsou
953a1897c0cSGleb Kurtsou# }}}
954a1897c0cSGleb Kurtsou
955a1897c0cSGleb Kurtsoudef list_str(l):
956a1897c0cSGleb Kurtsou    l = [ str(x) for x in l ]
957a1897c0cSGleb Kurtsou    l.sort()
958a1897c0cSGleb Kurtsou    return ', '.join(l)
959a1897c0cSGleb Kurtsou
960a1897c0cSGleb Kurtsoudef names_ver_str(vername, names):
961a1897c0cSGleb Kurtsou    return list_str([ x + "@" + vername for x in names ])
962a1897c0cSGleb Kurtsou
963a1897c0cSGleb Kurtsoudef common_symbols(origlib, newlib):
964a1897c0cSGleb Kurtsou    result = []
965a1897c0cSGleb Kurtsou    verdiff = ListDiff(origlib.versions.keys(), newlib.versions.keys())
966a1897c0cSGleb Kurtsou    if Config.verbose >= 1:
967749f65e3SCraig Rodrigues        print('Original versions:   ', list_str(verdiff.orig))
968749f65e3SCraig Rodrigues        print('New versions:        ', list_str(verdiff.new))
969a1897c0cSGleb Kurtsou    for vername in verdiff.added:
970749f65e3SCraig Rodrigues        print('Added version:       ', vername)
971749f65e3SCraig Rodrigues        print('    Added symbols:   ', \
972749f65e3SCraig Rodrigues                names_ver_str(vername, newlib.versions[vername].names()))
973a1897c0cSGleb Kurtsou    for vername in verdiff.removed:
974749f65e3SCraig Rodrigues        print('Removed version:     ', vername)
975749f65e3SCraig Rodrigues        print('    Removed symbols: ', \
976749f65e3SCraig Rodrigues                names_ver_str(vername, origlib.versions[vername].names()))
977a1897c0cSGleb Kurtsou    added = []
978a1897c0cSGleb Kurtsou    removed = []
979a1897c0cSGleb Kurtsou    for vername in verdiff.common:
980a1897c0cSGleb Kurtsou        origver = origlib.versions[vername]
981a1897c0cSGleb Kurtsou        newver = newlib.versions[vername]
982a1897c0cSGleb Kurtsou        namediff = ListDiff(origver.names(), newver.names())
983a1897c0cSGleb Kurtsou        if namediff.added:
984a1897c0cSGleb Kurtsou            added.append(names_ver_str(vername, namediff.added))
985a1897c0cSGleb Kurtsou        if namediff.removed:
986a1897c0cSGleb Kurtsou            removed.append(names_ver_str(vername, namediff.removed))
987a1897c0cSGleb Kurtsou        commonver = VersionMap(vername)
988a1897c0cSGleb Kurtsou        result.append(commonver)
989a1897c0cSGleb Kurtsou        for n in namediff.common:
990a1897c0cSGleb Kurtsou            sym = CommonSymbol(origver.symbols[n], newver.symbols[n])
991a1897c0cSGleb Kurtsou            commonver.append(sym)
992a1897c0cSGleb Kurtsou    if added:
993749f65e3SCraig Rodrigues        print('Added symbols:')
994a1897c0cSGleb Kurtsou        for i in added:
995749f65e3SCraig Rodrigues            print('    ', i)
996a1897c0cSGleb Kurtsou    if removed:
997749f65e3SCraig Rodrigues        print('Removed symbols:')
998a1897c0cSGleb Kurtsou        for i in removed:
999749f65e3SCraig Rodrigues            print('    ', i)
1000a1897c0cSGleb Kurtsou    return result
1001a1897c0cSGleb Kurtsou
1002a1897c0cSGleb Kurtsoudef cmp_symbols(commonver):
1003a1897c0cSGleb Kurtsou    for ver in commonver:
1004a1897c0cSGleb Kurtsou        names = ver.names();
1005a1897c0cSGleb Kurtsou        names.sort()
1006a1897c0cSGleb Kurtsou        for symname in names:
1007a1897c0cSGleb Kurtsou            sym = ver.symbols[symname]
1008c5f8185bSGleb Kurtsou            missing = sym.origsym.definition is None or sym.newsym.definition is None
1009c5f8185bSGleb Kurtsou            match = not missing and sym.origsym.definition == sym.newsym.definition
1010a1897c0cSGleb Kurtsou            if not match:
1011a1897c0cSGleb Kurtsou                App.result_code = 1
1012a1897c0cSGleb Kurtsou            if Config.verbose >= 1 or not match:
1013c5f8185bSGleb Kurtsou                if missing:
1014749f65e3SCraig Rodrigues                    print('%s: missing definition' % \
1015749f65e3SCraig Rodrigues                            (sym.origsym.name_ver,))
1016c5f8185bSGleb Kurtsou                    continue
1017749f65e3SCraig Rodrigues                print('%s: definitions %smatch' % \
1018749f65e3SCraig Rodrigues                        (sym.origsym.name_ver, "" if match else "mis"))
1019a1897c0cSGleb Kurtsou                if Config.dump or (not match and not Config.no_dump):
1020a1897c0cSGleb Kurtsou                    for x in [(sym.origsym, Config.origfile),
1021a1897c0cSGleb Kurtsou                            (sym.newsym, Config.newfile)]:
1022a1897c0cSGleb Kurtsou                        xsym = x[0]
1023a1897c0cSGleb Kurtsou                        xout = x[1].out
1024a1897c0cSGleb Kurtsou                        if not xsym.definition:
1025749f65e3SCraig Rodrigues                            print('\n// Definition not found: %s %s' % \
1026749f65e3SCraig Rodrigues                                    (xsym.name_ver, xsym.lib.libfile), file=xout)
1027a1897c0cSGleb Kurtsou                            continue
1028749f65e3SCraig Rodrigues                        print('\n// Definitions mismatch: %s %s' % \
1029749f65e3SCraig Rodrigues                                (xsym.name_ver, xsym.lib.libfile), file=xout)
1030a1897c0cSGleb Kurtsou                        pp = PrettyPrinter()
1031a1897c0cSGleb Kurtsou                        pp.run(xsym.definition)
1032a1897c0cSGleb Kurtsou                        for i in pp.nested():
1033749f65e3SCraig Rodrigues                            print(i, file=xout)
1034749f65e3SCraig Rodrigues                        print(pp.result(), file=xout)
1035a1897c0cSGleb Kurtsou
1036a1897c0cSGleb Kurtsoudef dump_symbols(commonver):
1037a1897c0cSGleb Kurtsou    class SymbolDump(object):
1038a1897c0cSGleb Kurtsou        def __init__(self, io_conf):
1039a1897c0cSGleb Kurtsou            self.io_conf = io_conf
1040a1897c0cSGleb Kurtsou            self.pp = PrettyPrinter()
1041a1897c0cSGleb Kurtsou            self.res = []
1042a1897c0cSGleb Kurtsou        def run(self, sym):
1043a1897c0cSGleb Kurtsou            r = self.pp.run(sym.definition)
1044a1897c0cSGleb Kurtsou            self.res.append('/* %s@%s */ %s' % (sym.name, sym.version, r))
1045a1897c0cSGleb Kurtsou        def finish(self):
1046749f65e3SCraig Rodrigues            print('\n// Symbol dump: version %s, library %s' % \
1047749f65e3SCraig Rodrigues                    (ver.name, self.io_conf.filename), file=self.io_conf.out)
1048a1897c0cSGleb Kurtsou            for i in self.pp.nested():
1049749f65e3SCraig Rodrigues                print(i, file=self.io_conf.out)
1050749f65e3SCraig Rodrigues            print('', file=self.io_conf.out)
1051a1897c0cSGleb Kurtsou            for i in self.res:
1052749f65e3SCraig Rodrigues                print(i, file=self.io_conf.out)
1053a1897c0cSGleb Kurtsou    for ver in commonver:
1054a1897c0cSGleb Kurtsou        names = sorted(ver.names());
1055a1897c0cSGleb Kurtsou        d_orig = SymbolDump(Config.origfile)
1056a1897c0cSGleb Kurtsou        d_new = SymbolDump(Config.newfile)
1057a1897c0cSGleb Kurtsou        for symname in names:
1058a1897c0cSGleb Kurtsou            sym = ver.symbols[symname]
1059a1897c0cSGleb Kurtsou            if not sym.origsym.definition or not sym.newsym.definition:
1060a1897c0cSGleb Kurtsou                # XXX
1061a1897c0cSGleb Kurtsou                warn(Config.w_symbol, 'Missing symbol definition: %s@%s' % \
1062a1897c0cSGleb Kurtsou                        (symname, ver.name))
1063a1897c0cSGleb Kurtsou                continue
1064a1897c0cSGleb Kurtsou            d_orig.run(sym.origsym)
1065a1897c0cSGleb Kurtsou            d_new.run(sym.newsym)
1066a1897c0cSGleb Kurtsou        d_orig.finish()
1067a1897c0cSGleb Kurtsou        d_new.finish()
1068a1897c0cSGleb Kurtsou
1069a1897c0cSGleb Kurtsouif __name__ == '__main__':
1070a1897c0cSGleb Kurtsou    Config.init()
1071a1897c0cSGleb Kurtsou    parser = optparse.OptionParser(usage="usage: %prog origlib newlib",
1072a1897c0cSGleb Kurtsou            version="%prog " + Config.version)
1073a1897c0cSGleb Kurtsou    parser.add_option('-v', '--verbose', action='count',
1074a1897c0cSGleb Kurtsou            help="verbose mode, may be specified several times")
1075a1897c0cSGleb Kurtsou    parser.add_option('--alias-prefix', action='append',
1076a1897c0cSGleb Kurtsou            help="name prefix to try for symbol alias lookup", metavar="STR")
1077a1897c0cSGleb Kurtsou    parser.add_option('--dump', action='store_true',
1078a1897c0cSGleb Kurtsou            help="dump symbol definitions")
1079a1897c0cSGleb Kurtsou    parser.add_option('--no-dump', action='store_true',
1080a1897c0cSGleb Kurtsou            help="disable dump for mismatched symbols")
1081a1897c0cSGleb Kurtsou    parser.add_option('--out-orig', action='store',
1082a1897c0cSGleb Kurtsou            help="result output file for original library", metavar="ORIGFILE")
1083a1897c0cSGleb Kurtsou    parser.add_option('--out-new', action='store',
1084a1897c0cSGleb Kurtsou            help="result output file for new library", metavar="NEWFILE")
1085c5f8185bSGleb Kurtsou    parser.add_option('--dwarfdump', action='store',
1086c5f8185bSGleb Kurtsou            help="path to dwarfdump executable", metavar="DWARFDUMP")
1087c5f8185bSGleb Kurtsou    parser.add_option('--objdump', action='store',
1088c5f8185bSGleb Kurtsou            help="path to objdump executable", metavar="OBJDUMP")
1089a1897c0cSGleb Kurtsou    parser.add_option('--exclude-ver', action='append', metavar="RE")
1090a1897c0cSGleb Kurtsou    parser.add_option('--include-ver', action='append', metavar="RE")
1091a1897c0cSGleb Kurtsou    parser.add_option('--exclude-sym', action='append', metavar="RE")
1092a1897c0cSGleb Kurtsou    parser.add_option('--include-sym', action='append', metavar="RE")
1093c5f8185bSGleb Kurtsou    parser.add_option('--no-exclude-sym-default', action='store_true',
1094c5f8185bSGleb Kurtsou            help="don't exclude special symbols like _init, _end, __bss_start")
1095a1897c0cSGleb Kurtsou    for opt in ['alias', 'cached', 'symbol']:
1096a1897c0cSGleb Kurtsou        parser.add_option("--w-" + opt,
1097a1897c0cSGleb Kurtsou                action="store_true", dest="w_" + opt)
1098a1897c0cSGleb Kurtsou        parser.add_option("--w-no-" + opt,
1099a1897c0cSGleb Kurtsou                action="store_false", dest="w_" + opt)
1100a1897c0cSGleb Kurtsou    (opts, args) = parser.parse_args()
1101a1897c0cSGleb Kurtsou
1102a1897c0cSGleb Kurtsou    if len(args) != 2:
1103a1897c0cSGleb Kurtsou        parser.print_help()
1104a1897c0cSGleb Kurtsou        sys.exit(-1)
1105c5f8185bSGleb Kurtsou    if opts.dwarfdump:
1106c5f8185bSGleb Kurtsou        Config.dwarfdump = opts.dwarfdump
1107c5f8185bSGleb Kurtsou    if opts.objdump:
1108c5f8185bSGleb Kurtsou        Config.objdump = opts.objdump
1109a1897c0cSGleb Kurtsou    if opts.out_orig:
1110a1897c0cSGleb Kurtsou        Config.origfile.init(opts.out_orig)
1111a1897c0cSGleb Kurtsou    if opts.out_new:
1112a1897c0cSGleb Kurtsou        Config.newfile.init(opts.out_new)
1113a1897c0cSGleb Kurtsou    if opts.no_dump:
1114a1897c0cSGleb Kurtsou        Config.dump = False
1115a1897c0cSGleb Kurtsou        Config.no_dump = True
1116a1897c0cSGleb Kurtsou    if opts.dump:
1117a1897c0cSGleb Kurtsou        Config.dump = True
1118a1897c0cSGleb Kurtsou        Config.no_dump = False
1119a1897c0cSGleb Kurtsou        Config.verbose = 1
1120a1897c0cSGleb Kurtsou    if opts.verbose:
1121a1897c0cSGleb Kurtsou        Config.verbose = opts.verbose
1122a1897c0cSGleb Kurtsou    if opts.alias_prefix:
1123a1897c0cSGleb Kurtsou        Config.alias_prefixes = opts.alias_prefix
1124a1897c0cSGleb Kurtsou        Config.alias_prefixes.sort(key=lambda x: -len(x))
1125a1897c0cSGleb Kurtsou    for (k, v) in ({ '_sym': Config.symbol_filter,
1126a1897c0cSGleb Kurtsou            '_ver': Config.version_filter }).items():
1127a1897c0cSGleb Kurtsou        for a in [ 'exclude', 'include' ]:
1128a1897c0cSGleb Kurtsou            opt = getattr(opts, a + k)
1129a1897c0cSGleb Kurtsou            if opt:
1130a1897c0cSGleb Kurtsou                getattr(v, a).extend(opt)
1131c5f8185bSGleb Kurtsou    if not opts.no_exclude_sym_default:
1132c5f8185bSGleb Kurtsou        Config.symbol_filter.exclude.extend(Config.exclude_sym_default)
1133a1897c0cSGleb Kurtsou    Config.version_filter.compile()
1134a1897c0cSGleb Kurtsou    Config.symbol_filter.compile()
1135a1897c0cSGleb Kurtsou    for w in ['w_alias', 'w_cached', 'w_symbol']:
1136a1897c0cSGleb Kurtsou        if hasattr(opts, w):
1137a1897c0cSGleb Kurtsou            v = getattr(opts, w)
1138a1897c0cSGleb Kurtsou            if v != None:
1139a1897c0cSGleb Kurtsou                setattr(Config, w, v)
1140a1897c0cSGleb Kurtsou
1141a1897c0cSGleb Kurtsou    (Config.origfile.filename, Config.newfile.filename) = (args[0], args[1])
1142a1897c0cSGleb Kurtsou
1143a1897c0cSGleb Kurtsou    origlib = Shlib(Config.origfile.filename)
1144a1897c0cSGleb Kurtsou    origlib.parse()
1145a1897c0cSGleb Kurtsou    newlib = Shlib(Config.newfile.filename)
1146a1897c0cSGleb Kurtsou    newlib.parse()
1147a1897c0cSGleb Kurtsou
1148a1897c0cSGleb Kurtsou    commonver = common_symbols(origlib, newlib)
1149a1897c0cSGleb Kurtsou    if Config.dump:
1150a1897c0cSGleb Kurtsou        dump_symbols(commonver)
1151a1897c0cSGleb Kurtsou    cmp_symbols(commonver)
1152a1897c0cSGleb Kurtsou    if Config.verbose >= 4:
1153749f65e3SCraig Rodrigues        print(Dwarf.cmpcache.stats.show('Cmp'))
1154749f65e3SCraig Rodrigues        print(DwarfdumpParser.tagcache_stats.show('Dwarf tag'))
1155a1897c0cSGleb Kurtsou
1156a1897c0cSGleb Kurtsou    sys.exit(App.result_code)
1157