Source code for envi.resolver
"""
The API describing what it means to be an envi compliant
symbol resolver.
"""
import types
[docs]class Symbol:
def __init__(self, name, value, size=0, fname=None):
self.name = name
self.value = value
self.size = size
self.fname = fname
def __eq__(self, other):
if not isinstance(other, Symbol):
return False
return long(self) == long(other)
def __coerce__(self, value):
t = type(value)
if t == types.NoneType:
return (True, False)
return (value, t(self.value))
def __hash__(self):
return hash(long(self))
def __long__(self):
return long(self.value)
def __int__(self):
return int(self.value)
def __len__(self):
return self.size
def __str__(self):
if self.fname != None:
return "%s.%s" % (self.fname, self.name)
return self.name
def __repr__(self):
return str(self)
[docs]class SymbolResolver:
"""
NOTE: Nothing should reach directly into a SymbolResolver!
"""
def __init__(self, width=4, casesens=True):
self.width = width
self.widthmask = (2**(width*8))-1
self.casesens = casesens
# Lets use 4096 byte buckes for now
self.bucketsize = 4096
self.bucketmask = self.widthmask ^ (self.bucketsize-1)
self.buckets = {}
self.symnames = {}
self.symaddrs = {}
[docs] def delSymbol(self, sym):
"""
Delete a symbol from the resolver's namespace
"""
symval = long(sym)
self.symaddrs.pop(symval, None)
bbase = symval & self.bucketmask
while bbase < symval:
bucket = self.buckets.get(bbase)
bucket.remove(sym)
bbase += self.bucketsize
subres = None
if sym.fname != None:
subres = self.symnames.get(sym.fname)
# Potentially del it from the sub resolver's namespace
if subres != None:
subres.delSymbol(sym)
# Otherwise del it from our namespace
else:
symname = sym.name
if not self.casesens:
symname = symname.lower()
self.symnames.pop(symname, None)
[docs] def addSymbol(self, sym):
"""
Add a symbol to the resolver.
"""
# If the symbol has an fname, add it to the namespace
# for the FileSymbol inside us rather than our namespace.
symval = long(sym)
self.symaddrs[symval] = sym
bbase = symval & self.bucketmask
while bbase < symval:
bucket = self.buckets.get(bbase)
if bucket == None:
bucket = []
self.buckets[bbase] = bucket
bucket.append(sym)
bbase += self.bucketsize
subres = None
if sym.fname != None:
subres = self.symnames.get(sym.fname)
# Potentially add it to the sub resolver's namespace
if subres != None:
subres.addSymbol(sym)
# Otherwise add it to our namespace
else:
symname = sym.name
if not self.casesens:
symname = symname.lower()
self.symnames[symname] = sym
[docs] def getSymByName(self, name):
if not self.casesens:
name = name.lower()
return self.symnames.get(name)
[docs] def getSymByAddr(self, va, exact=True):
"""
Return a symbol object for the given virtual address.
"""
va = va & self.widthmask
sym = self.symaddrs.get(va)
if sym != None:
return sym
if not exact:
b = va & self.bucketmask
best = 999999999
while sym == None:
bucket = self.buckets.get(b)
if bucket != None:
for s in bucket:
sva = long(s)
if sva > va:
continue
offset = va - sva
if offset < best:
best = offset
sym = s
# If we get more than 8k away, just get out...
if va - b > 8192:
break
# Move back to the previous bucket.
b -= self.bucketsize
# If we resolve a sub-resolver, see if he
# has finer resolution than we do...
if isinstance(sym, SymbolResolver):
ssym = sym.getSymByAddr(va, exact=exact)
if ssym != None:
return ssym
return sym
[docs] def getSymList(self):
"""
Return a list of the symbols which are contained in this resolver.
"""
return self.symaddrs.values()
[docs] def getSymHint(self, va, hidx):
"""
May be used by symbol resolvers who know what type they are
resolving to store and retrieve "hints" with indexes.
Used specifically by opcode render methods to resolve
any memory dereference info for a given operand.
NOTE: These are mostly symbolic references to FRAME LOCAL
names....
"""
return None
# Some extension types
[docs]class FunctionSymbol(Symbol):
"""
Used to represent functions.
"""
def __repr__(self):
return "%s.%s()" % (self.fname, self.name)
[docs]class SectionSymbol(Symbol):
"""
Used for file sections/segments.
"""
def __repr__(self):
return "%s[%s]" % (self.fname,self.name)
[docs]class FileSymbol(Symbol,SymbolResolver):
"""
A file symbol is both a symbol resolver of it's own, and
a symbol.
File symbols are used to do heirarchal symbol lookups and don't
actually add anything but the name to their lookup (it is assumed
that the parent Resolver of the FileSymbol takes care of addr lookups.
"""
def __init__(self, fname, base, size, width=4):
SymbolResolver.__init__(self, width=width)
Symbol.__init__(self, fname, base, size)
def __getattr__(self, name):
"""
File symbols may be dereferenced like python objects to resolve
symbols within them.
"""
ret = self.getSymByName(name)
if ret == None:
raise AttributeError("%s has no symbol %s" % (self.name,name))
return ret
def __getitem__(self, name):
"""
Allow dictionary style access for mangled incompatible names...
"""
ret = self.getSymByName(name)
if ret == None:
raise KeyError("%s has no symbol %s" % (self.name,name))
return ret