mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-26 09:08:30 +00:00
scripts: Include global/section info in collect_syms, added Sym
We have this info, might as well expose it for scripts to use. Unfortunately this extra info did make tuple unpacking a bit of a mess, especially in scripts that don't use this extra info, so I've added a small Sym class similar to DwarfEntry in collect_dwarf_info. This is useful for some ongoing stack.py rework.
This commit is contained in:
@@ -158,6 +158,21 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
class Sym(co.namedtuple('Sym', [
|
||||||
|
'name', 'global_', 'section', 'addr', 'size'])):
|
||||||
|
__slots__ = ()
|
||||||
|
def __new__(cls, name, global_, section, addr, size):
|
||||||
|
return super().__new__(cls, name, global_, section, addr, size)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r, %r, 0x%x, 0x%x)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.global_,
|
||||||
|
self.section,
|
||||||
|
self.addr,
|
||||||
|
self.size)
|
||||||
|
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
def __init__(self, syms):
|
def __init__(self, syms):
|
||||||
self.syms = syms
|
self.syms = syms
|
||||||
@@ -168,12 +183,13 @@ class SymInfo:
|
|||||||
# organize by symbol, note multiple symbols can share a name
|
# organize by symbol, note multiple symbols can share a name
|
||||||
if not hasattr(self, '_by_sym'):
|
if not hasattr(self, '_by_sym'):
|
||||||
by_sym = {}
|
by_sym = {}
|
||||||
for sym, addr, size in self.syms:
|
for sym in self.syms:
|
||||||
if sym not in by_sym:
|
if sym.name not in by_sym:
|
||||||
by_sym[sym] = []
|
by_sym[sym.name] = []
|
||||||
if (addr, size) not in by_sym[sym]:
|
if sym not in by_sym[sym.name]:
|
||||||
by_sym[sym].append((addr, size))
|
by_sym[sym.name].append(sym)
|
||||||
self._by_sym = by_sym
|
self._by_sym = by_sym
|
||||||
|
|
||||||
return self._by_sym.get(k, d)
|
return self._by_sym.get(k, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -183,21 +199,21 @@ class SymInfo:
|
|||||||
if not hasattr(self, '_by_addr'):
|
if not hasattr(self, '_by_addr'):
|
||||||
# sort and keep largest/first when duplicates
|
# sort and keep largest/first when duplicates
|
||||||
syms = self.syms.copy()
|
syms = self.syms.copy()
|
||||||
syms.sort(key=lambda x: (x[1], -x[2], x[0]))
|
syms.sort(key=lambda x: (x.addr, -x.size))
|
||||||
|
|
||||||
by_addr = []
|
by_addr = []
|
||||||
for name, addr, size in syms:
|
for sym in syms:
|
||||||
if (len(by_addr) == 0
|
if (len(by_addr) == 0
|
||||||
or by_addr[-1][0] != addr):
|
or by_addr[-1].addr != sym.addr):
|
||||||
by_addr.append((name, addr, size))
|
by_addr.append(sym)
|
||||||
self._by_addr = by_addr
|
self._by_addr = by_addr
|
||||||
|
|
||||||
# find sym by range
|
# find sym by range
|
||||||
i = bisect.bisect(self._by_addr, k,
|
i = bisect.bisect(self._by_addr, k,
|
||||||
key=lambda x: x[1])
|
key=lambda x: x.addr)
|
||||||
# check that we're actually in this sym's size
|
# check that we're actually in this sym's size
|
||||||
if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]:
|
if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size:
|
||||||
return self._by_addr[i-1][0]
|
return self._by_addr[i-1]
|
||||||
else:
|
else:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -216,7 +232,16 @@ class SymInfo:
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.syms)
|
return iter(self.syms)
|
||||||
|
|
||||||
def collect_syms(obj_path, sections=None, global_=False, *,
|
def globals(self):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
if sym.global_])
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
# note we accept prefixes
|
||||||
|
if s.startswith(section)])
|
||||||
|
|
||||||
|
def collect_syms(obj_path, global_=False, sections=None, *,
|
||||||
objdump_path=OBJDUMP_PATH,
|
objdump_path=OBJDUMP_PATH,
|
||||||
**args):
|
**args):
|
||||||
symbol_pattern = re.compile(
|
symbol_pattern = re.compile(
|
||||||
@@ -250,7 +275,8 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
# u => unique global
|
# u => unique global
|
||||||
# => neither
|
# => neither
|
||||||
# ! => local + global
|
# ! => local + global
|
||||||
if global_ and scope in 'l ':
|
global__ = scope not in 'l '
|
||||||
|
if global_ and not global__:
|
||||||
continue
|
continue
|
||||||
# filter by section? note we accept prefixes
|
# filter by section? note we accept prefixes
|
||||||
if (sections is not None
|
if (sections is not None
|
||||||
@@ -261,7 +287,7 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
if not size:
|
if not size:
|
||||||
continue
|
continue
|
||||||
# note multiple symbols can share a name
|
# note multiple symbols can share a name
|
||||||
syms.append((name, addr, size))
|
syms.append(Sym(name, global__, section, addr, size))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise sp.CalledProcessError(proc.returncode, proc.args)
|
raise sp.CalledProcessError(proc.returncode, proc.args)
|
||||||
@@ -487,14 +513,14 @@ def collect(obj_paths, *,
|
|||||||
**args)
|
**args)
|
||||||
|
|
||||||
# map function sizes to debug symbols
|
# map function sizes to debug symbols
|
||||||
for sym, _, size in syms:
|
for sym in syms:
|
||||||
# discard internal functions
|
# discard internal functions
|
||||||
if not everything and sym.startswith('__'):
|
if not everything and sym.name.startswith('__'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# find best matching dwarf entry, this may be slightly different
|
# find best matching dwarf entry, this may be slightly different
|
||||||
# due to optimizations
|
# due to optimizations
|
||||||
entry = info.get(sym)
|
entry = info.get(sym.name)
|
||||||
|
|
||||||
# if we have no file guess from obj path
|
# if we have no file guess from obj path
|
||||||
if entry is not None and 'DW_AT_decl_file' in entry:
|
if entry is not None and 'DW_AT_decl_file' in entry:
|
||||||
@@ -514,7 +540,7 @@ def collect(obj_paths, *,
|
|||||||
os.path.abspath(file)]) == os.getcwd():
|
os.path.abspath(file)]) == os.getcwd():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
results.append(CodeResult(file, sym, size))
|
results.append(CodeResult(file, sym.name, sym.size))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|||||||
@@ -167,6 +167,21 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
class Sym(co.namedtuple('Sym', [
|
||||||
|
'name', 'global_', 'section', 'addr', 'size'])):
|
||||||
|
__slots__ = ()
|
||||||
|
def __new__(cls, name, global_, section, addr, size):
|
||||||
|
return super().__new__(cls, name, global_, section, addr, size)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r, %r, 0x%x, 0x%x)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.global_,
|
||||||
|
self.section,
|
||||||
|
self.addr,
|
||||||
|
self.size)
|
||||||
|
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
def __init__(self, syms):
|
def __init__(self, syms):
|
||||||
self.syms = syms
|
self.syms = syms
|
||||||
@@ -177,12 +192,13 @@ class SymInfo:
|
|||||||
# organize by symbol, note multiple symbols can share a name
|
# organize by symbol, note multiple symbols can share a name
|
||||||
if not hasattr(self, '_by_sym'):
|
if not hasattr(self, '_by_sym'):
|
||||||
by_sym = {}
|
by_sym = {}
|
||||||
for sym, addr, size in self.syms:
|
for sym in self.syms:
|
||||||
if sym not in by_sym:
|
if sym.name not in by_sym:
|
||||||
by_sym[sym] = []
|
by_sym[sym.name] = []
|
||||||
if (addr, size) not in by_sym[sym]:
|
if sym not in by_sym[sym.name]:
|
||||||
by_sym[sym].append((addr, size))
|
by_sym[sym.name].append(sym)
|
||||||
self._by_sym = by_sym
|
self._by_sym = by_sym
|
||||||
|
|
||||||
return self._by_sym.get(k, d)
|
return self._by_sym.get(k, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -192,21 +208,21 @@ class SymInfo:
|
|||||||
if not hasattr(self, '_by_addr'):
|
if not hasattr(self, '_by_addr'):
|
||||||
# sort and keep largest/first when duplicates
|
# sort and keep largest/first when duplicates
|
||||||
syms = self.syms.copy()
|
syms = self.syms.copy()
|
||||||
syms.sort(key=lambda x: (x[1], -x[2], x[0]))
|
syms.sort(key=lambda x: (x.addr, -x.size))
|
||||||
|
|
||||||
by_addr = []
|
by_addr = []
|
||||||
for name, addr, size in syms:
|
for sym in syms:
|
||||||
if (len(by_addr) == 0
|
if (len(by_addr) == 0
|
||||||
or by_addr[-1][0] != addr):
|
or by_addr[-1].addr != sym.addr):
|
||||||
by_addr.append((name, addr, size))
|
by_addr.append(sym)
|
||||||
self._by_addr = by_addr
|
self._by_addr = by_addr
|
||||||
|
|
||||||
# find sym by range
|
# find sym by range
|
||||||
i = bisect.bisect(self._by_addr, k,
|
i = bisect.bisect(self._by_addr, k,
|
||||||
key=lambda x: x[1])
|
key=lambda x: x.addr)
|
||||||
# check that we're actually in this sym's size
|
# check that we're actually in this sym's size
|
||||||
if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]:
|
if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size:
|
||||||
return self._by_addr[i-1][0]
|
return self._by_addr[i-1]
|
||||||
else:
|
else:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -225,7 +241,16 @@ class SymInfo:
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.syms)
|
return iter(self.syms)
|
||||||
|
|
||||||
def collect_syms(obj_path, sections=None, global_=False, *,
|
def globals(self):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
if sym.global_])
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
# note we accept prefixes
|
||||||
|
if s.startswith(section)])
|
||||||
|
|
||||||
|
def collect_syms(obj_path, global_=False, sections=None, *,
|
||||||
objdump_path=OBJDUMP_PATH,
|
objdump_path=OBJDUMP_PATH,
|
||||||
**args):
|
**args):
|
||||||
symbol_pattern = re.compile(
|
symbol_pattern = re.compile(
|
||||||
@@ -259,7 +284,8 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
# u => unique global
|
# u => unique global
|
||||||
# => neither
|
# => neither
|
||||||
# ! => local + global
|
# ! => local + global
|
||||||
if global_ and scope in 'l ':
|
global__ = scope not in 'l '
|
||||||
|
if global_ and not global__:
|
||||||
continue
|
continue
|
||||||
# filter by section? note we accept prefixes
|
# filter by section? note we accept prefixes
|
||||||
if (sections is not None
|
if (sections is not None
|
||||||
@@ -270,7 +296,7 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
if not size:
|
if not size:
|
||||||
continue
|
continue
|
||||||
# note multiple symbols can share a name
|
# note multiple symbols can share a name
|
||||||
syms.append((name, addr, size))
|
syms.append(Sym(name, global__, section, addr, size))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise sp.CalledProcessError(proc.returncode, proc.args)
|
raise sp.CalledProcessError(proc.returncode, proc.args)
|
||||||
@@ -649,13 +675,13 @@ def collect(obj_paths, *,
|
|||||||
return children, notes
|
return children, notes
|
||||||
|
|
||||||
# find each function's context
|
# find each function's context
|
||||||
for sym, _, _ in syms:
|
for sym in syms:
|
||||||
# discard internal functions
|
# discard internal functions
|
||||||
if not everything and sym.startswith('__'):
|
if not everything and sym.name.startswith('__'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# find best matching dwarf entry
|
# find best matching dwarf entry
|
||||||
entry = info.get(sym)
|
entry = info.get(sym.name)
|
||||||
|
|
||||||
# skip non-functions
|
# skip non-functions
|
||||||
if entry is None or entry.tag != 'DW_TAG_subprogram':
|
if entry is None or entry.tag != 'DW_TAG_subprogram':
|
||||||
|
|||||||
@@ -158,6 +158,21 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
class Sym(co.namedtuple('Sym', [
|
||||||
|
'name', 'global_', 'section', 'addr', 'size'])):
|
||||||
|
__slots__ = ()
|
||||||
|
def __new__(cls, name, global_, section, addr, size):
|
||||||
|
return super().__new__(cls, name, global_, section, addr, size)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r, %r, 0x%x, 0x%x)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.global_,
|
||||||
|
self.section,
|
||||||
|
self.addr,
|
||||||
|
self.size)
|
||||||
|
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
def __init__(self, syms):
|
def __init__(self, syms):
|
||||||
self.syms = syms
|
self.syms = syms
|
||||||
@@ -168,12 +183,13 @@ class SymInfo:
|
|||||||
# organize by symbol, note multiple symbols can share a name
|
# organize by symbol, note multiple symbols can share a name
|
||||||
if not hasattr(self, '_by_sym'):
|
if not hasattr(self, '_by_sym'):
|
||||||
by_sym = {}
|
by_sym = {}
|
||||||
for sym, addr, size in self.syms:
|
for sym in self.syms:
|
||||||
if sym not in by_sym:
|
if sym.name not in by_sym:
|
||||||
by_sym[sym] = []
|
by_sym[sym.name] = []
|
||||||
if (addr, size) not in by_sym[sym]:
|
if sym not in by_sym[sym.name]:
|
||||||
by_sym[sym].append((addr, size))
|
by_sym[sym.name].append(sym)
|
||||||
self._by_sym = by_sym
|
self._by_sym = by_sym
|
||||||
|
|
||||||
return self._by_sym.get(k, d)
|
return self._by_sym.get(k, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -183,21 +199,21 @@ class SymInfo:
|
|||||||
if not hasattr(self, '_by_addr'):
|
if not hasattr(self, '_by_addr'):
|
||||||
# sort and keep largest/first when duplicates
|
# sort and keep largest/first when duplicates
|
||||||
syms = self.syms.copy()
|
syms = self.syms.copy()
|
||||||
syms.sort(key=lambda x: (x[1], -x[2], x[0]))
|
syms.sort(key=lambda x: (x.addr, -x.size))
|
||||||
|
|
||||||
by_addr = []
|
by_addr = []
|
||||||
for name, addr, size in syms:
|
for sym in syms:
|
||||||
if (len(by_addr) == 0
|
if (len(by_addr) == 0
|
||||||
or by_addr[-1][0] != addr):
|
or by_addr[-1].addr != sym.addr):
|
||||||
by_addr.append((name, addr, size))
|
by_addr.append(sym)
|
||||||
self._by_addr = by_addr
|
self._by_addr = by_addr
|
||||||
|
|
||||||
# find sym by range
|
# find sym by range
|
||||||
i = bisect.bisect(self._by_addr, k,
|
i = bisect.bisect(self._by_addr, k,
|
||||||
key=lambda x: x[1])
|
key=lambda x: x.addr)
|
||||||
# check that we're actually in this sym's size
|
# check that we're actually in this sym's size
|
||||||
if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]:
|
if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size:
|
||||||
return self._by_addr[i-1][0]
|
return self._by_addr[i-1]
|
||||||
else:
|
else:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -216,7 +232,16 @@ class SymInfo:
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.syms)
|
return iter(self.syms)
|
||||||
|
|
||||||
def collect_syms(obj_path, sections=None, global_=False, *,
|
def globals(self):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
if sym.global_])
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
# note we accept prefixes
|
||||||
|
if s.startswith(section)])
|
||||||
|
|
||||||
|
def collect_syms(obj_path, global_=False, sections=None, *,
|
||||||
objdump_path=OBJDUMP_PATH,
|
objdump_path=OBJDUMP_PATH,
|
||||||
**args):
|
**args):
|
||||||
symbol_pattern = re.compile(
|
symbol_pattern = re.compile(
|
||||||
@@ -250,7 +275,8 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
# u => unique global
|
# u => unique global
|
||||||
# => neither
|
# => neither
|
||||||
# ! => local + global
|
# ! => local + global
|
||||||
if global_ and scope in 'l ':
|
global__ = scope not in 'l '
|
||||||
|
if global_ and not global__:
|
||||||
continue
|
continue
|
||||||
# filter by section? note we accept prefixes
|
# filter by section? note we accept prefixes
|
||||||
if (sections is not None
|
if (sections is not None
|
||||||
@@ -261,7 +287,7 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
if not size:
|
if not size:
|
||||||
continue
|
continue
|
||||||
# note multiple symbols can share a name
|
# note multiple symbols can share a name
|
||||||
syms.append((name, addr, size))
|
syms.append(Sym(name, global__, section, addr, size))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise sp.CalledProcessError(proc.returncode, proc.args)
|
raise sp.CalledProcessError(proc.returncode, proc.args)
|
||||||
@@ -487,14 +513,14 @@ def collect(obj_paths, *,
|
|||||||
**args)
|
**args)
|
||||||
|
|
||||||
# map function sizes to debug symbols
|
# map function sizes to debug symbols
|
||||||
for sym, _, size in syms:
|
for sym in syms:
|
||||||
# discard internal functions
|
# discard internal functions
|
||||||
if not everything and sym.startswith('__'):
|
if not everything and sym.name.startswith('__'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# find best matching dwarf entry, this may be slightly different
|
# find best matching dwarf entry, this may be slightly different
|
||||||
# due to optimizations
|
# due to optimizations
|
||||||
entry = info.get(sym)
|
entry = info.get(sym.name)
|
||||||
|
|
||||||
# if we have no file guess from obj path
|
# if we have no file guess from obj path
|
||||||
if entry is not None and 'DW_AT_decl_file' in entry:
|
if entry is not None and 'DW_AT_decl_file' in entry:
|
||||||
@@ -514,7 +540,7 @@ def collect(obj_paths, *,
|
|||||||
os.path.abspath(file)]) == os.getcwd():
|
os.path.abspath(file)]) == os.getcwd():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
results.append(DataResult(file, sym, size))
|
results.append(DataResult(file, sym.name, sym.size))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|||||||
@@ -260,6 +260,21 @@ def multiprocessing_cache(f):
|
|||||||
|
|
||||||
return multiprocessing_cache
|
return multiprocessing_cache
|
||||||
|
|
||||||
|
class Sym(co.namedtuple('Sym', [
|
||||||
|
'name', 'global_', 'section', 'addr', 'size'])):
|
||||||
|
__slots__ = ()
|
||||||
|
def __new__(cls, name, global_, section, addr, size):
|
||||||
|
return super().__new__(cls, name, global_, section, addr, size)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r, %r, 0x%x, 0x%x)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.global_,
|
||||||
|
self.section,
|
||||||
|
self.addr,
|
||||||
|
self.size)
|
||||||
|
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
def __init__(self, syms):
|
def __init__(self, syms):
|
||||||
self.syms = syms
|
self.syms = syms
|
||||||
@@ -270,12 +285,13 @@ class SymInfo:
|
|||||||
# organize by symbol, note multiple symbols can share a name
|
# organize by symbol, note multiple symbols can share a name
|
||||||
if not hasattr(self, '_by_sym'):
|
if not hasattr(self, '_by_sym'):
|
||||||
by_sym = {}
|
by_sym = {}
|
||||||
for sym, addr, size in self.syms:
|
for sym in self.syms:
|
||||||
if sym not in by_sym:
|
if sym.name not in by_sym:
|
||||||
by_sym[sym] = []
|
by_sym[sym.name] = []
|
||||||
if (addr, size) not in by_sym[sym]:
|
if sym not in by_sym[sym.name]:
|
||||||
by_sym[sym].append((addr, size))
|
by_sym[sym.name].append(sym)
|
||||||
self._by_sym = by_sym
|
self._by_sym = by_sym
|
||||||
|
|
||||||
return self._by_sym.get(k, d)
|
return self._by_sym.get(k, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -285,21 +301,21 @@ class SymInfo:
|
|||||||
if not hasattr(self, '_by_addr'):
|
if not hasattr(self, '_by_addr'):
|
||||||
# sort and keep largest/first when duplicates
|
# sort and keep largest/first when duplicates
|
||||||
syms = self.syms.copy()
|
syms = self.syms.copy()
|
||||||
syms.sort(key=lambda x: (x[1], -x[2], x[0]))
|
syms.sort(key=lambda x: (x.addr, -x.size))
|
||||||
|
|
||||||
by_addr = []
|
by_addr = []
|
||||||
for name, addr, size in syms:
|
for sym in syms:
|
||||||
if (len(by_addr) == 0
|
if (len(by_addr) == 0
|
||||||
or by_addr[-1][0] != addr):
|
or by_addr[-1].addr != sym.addr):
|
||||||
by_addr.append((name, addr, size))
|
by_addr.append(sym)
|
||||||
self._by_addr = by_addr
|
self._by_addr = by_addr
|
||||||
|
|
||||||
# find sym by range
|
# find sym by range
|
||||||
i = bisect.bisect(self._by_addr, k,
|
i = bisect.bisect(self._by_addr, k,
|
||||||
key=lambda x: x[1])
|
key=lambda x: x.addr)
|
||||||
# check that we're actually in this sym's size
|
# check that we're actually in this sym's size
|
||||||
if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]:
|
if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size:
|
||||||
return self._by_addr[i-1][0]
|
return self._by_addr[i-1]
|
||||||
else:
|
else:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -318,8 +334,17 @@ class SymInfo:
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.syms)
|
return iter(self.syms)
|
||||||
|
|
||||||
|
def globals(self):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
if sym.global_])
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
# note we accept prefixes
|
||||||
|
if s.startswith(section)])
|
||||||
|
|
||||||
@multiprocessing_cache
|
@multiprocessing_cache
|
||||||
def collect_syms(obj_path, sections=None, global_=False, *,
|
def collect_syms(obj_path, global_=False, sections=None, *,
|
||||||
objdump_path=OBJDUMP_PATH,
|
objdump_path=OBJDUMP_PATH,
|
||||||
**args):
|
**args):
|
||||||
symbol_pattern = re.compile(
|
symbol_pattern = re.compile(
|
||||||
@@ -353,7 +378,8 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
# u => unique global
|
# u => unique global
|
||||||
# => neither
|
# => neither
|
||||||
# ! => local + global
|
# ! => local + global
|
||||||
if global_ and scope in 'l ':
|
global__ = scope not in 'l '
|
||||||
|
if global_ and not global__:
|
||||||
continue
|
continue
|
||||||
# filter by section? note we accept prefixes
|
# filter by section? note we accept prefixes
|
||||||
if (sections is not None
|
if (sections is not None
|
||||||
@@ -364,7 +390,7 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
if not size:
|
if not size:
|
||||||
continue
|
continue
|
||||||
# note multiple symbols can share a name
|
# note multiple symbols can share a name
|
||||||
syms.append((name, addr, size))
|
syms.append(Sym(name, global__, section, addr, size))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise sp.CalledProcessError(proc.returncode, proc.args)
|
raise sp.CalledProcessError(proc.returncode, proc.args)
|
||||||
@@ -633,16 +659,16 @@ def collect_decompressed(path, *,
|
|||||||
sym_addr_ = addr_ - off
|
sym_addr_ = addr_ - off
|
||||||
|
|
||||||
# track possible deltas?
|
# track possible deltas?
|
||||||
for sym_addr, size in syms[sym]:
|
for sym_ in syms[sym]:
|
||||||
delta = sym_addr - sym_addr_
|
delta = sym_.addr - sym_addr_
|
||||||
if delta not in deltas[dso]:
|
if delta not in deltas[dso]:
|
||||||
deltas[dso][delta] = sum(
|
deltas[dso][delta] = sum(
|
||||||
abs(a_+delta - a)
|
abs(a_+delta - a)
|
||||||
for s, (a_, _) in syms_[dso].items()
|
for s, (a_, _) in syms_[dso].items()
|
||||||
for a, _ in syms[s])
|
for a, _ in syms[s])
|
||||||
for delta in deltas[dso].keys():
|
for delta in deltas[dso].keys():
|
||||||
deltas[dso][delta] += abs(sym_addr_+delta - sym_addr)
|
deltas[dso][delta] += abs(sym_addr_+delta - sym_.addr)
|
||||||
syms_[dso][sym] = sym_addr_, size
|
syms_[dso][sym] = sym_addr_, sym_.size
|
||||||
|
|
||||||
# guess the best delta
|
# guess the best delta
|
||||||
delta, _ = min(deltas[dso].items(),
|
delta, _ = min(deltas[dso].items(),
|
||||||
|
|||||||
@@ -167,6 +167,21 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
class Sym(co.namedtuple('Sym', [
|
||||||
|
'name', 'global_', 'section', 'addr', 'size'])):
|
||||||
|
__slots__ = ()
|
||||||
|
def __new__(cls, name, global_, section, addr, size):
|
||||||
|
return super().__new__(cls, name, global_, section, addr, size)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '%s(%r, %r, %r, 0x%x, 0x%x)' % (
|
||||||
|
self.__class__.__name__,
|
||||||
|
self.name,
|
||||||
|
self.global_,
|
||||||
|
self.section,
|
||||||
|
self.addr,
|
||||||
|
self.size)
|
||||||
|
|
||||||
class SymInfo:
|
class SymInfo:
|
||||||
def __init__(self, syms):
|
def __init__(self, syms):
|
||||||
self.syms = syms
|
self.syms = syms
|
||||||
@@ -177,12 +192,13 @@ class SymInfo:
|
|||||||
# organize by symbol, note multiple symbols can share a name
|
# organize by symbol, note multiple symbols can share a name
|
||||||
if not hasattr(self, '_by_sym'):
|
if not hasattr(self, '_by_sym'):
|
||||||
by_sym = {}
|
by_sym = {}
|
||||||
for sym, addr, size in self.syms:
|
for sym in self.syms:
|
||||||
if sym not in by_sym:
|
if sym.name not in by_sym:
|
||||||
by_sym[sym] = []
|
by_sym[sym.name] = []
|
||||||
if (addr, size) not in by_sym[sym]:
|
if sym not in by_sym[sym.name]:
|
||||||
by_sym[sym].append((addr, size))
|
by_sym[sym.name].append(sym)
|
||||||
self._by_sym = by_sym
|
self._by_sym = by_sym
|
||||||
|
|
||||||
return self._by_sym.get(k, d)
|
return self._by_sym.get(k, d)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -192,21 +208,21 @@ class SymInfo:
|
|||||||
if not hasattr(self, '_by_addr'):
|
if not hasattr(self, '_by_addr'):
|
||||||
# sort and keep largest/first when duplicates
|
# sort and keep largest/first when duplicates
|
||||||
syms = self.syms.copy()
|
syms = self.syms.copy()
|
||||||
syms.sort(key=lambda x: (x[1], -x[2], x[0]))
|
syms.sort(key=lambda x: (x.addr, -x.size))
|
||||||
|
|
||||||
by_addr = []
|
by_addr = []
|
||||||
for name, addr, size in syms:
|
for sym in syms:
|
||||||
if (len(by_addr) == 0
|
if (len(by_addr) == 0
|
||||||
or by_addr[-1][0] != addr):
|
or by_addr[-1].addr != sym.addr):
|
||||||
by_addr.append((name, addr, size))
|
by_addr.append(sym)
|
||||||
self._by_addr = by_addr
|
self._by_addr = by_addr
|
||||||
|
|
||||||
# find sym by range
|
# find sym by range
|
||||||
i = bisect.bisect(self._by_addr, k,
|
i = bisect.bisect(self._by_addr, k,
|
||||||
key=lambda x: x[1])
|
key=lambda x: x.addr)
|
||||||
# check that we're actually in this sym's size
|
# check that we're actually in this sym's size
|
||||||
if i > 0 and k < self._by_addr[i-1][1]+self._by_addr[i-1][2]:
|
if i > 0 and k < self._by_addr[i-1].addr+self._by_addr[i-1].size:
|
||||||
return self._by_addr[i-1][0]
|
return self._by_addr[i-1]
|
||||||
else:
|
else:
|
||||||
return d
|
return d
|
||||||
|
|
||||||
@@ -225,7 +241,16 @@ class SymInfo:
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.syms)
|
return iter(self.syms)
|
||||||
|
|
||||||
def collect_syms(obj_path, sections=None, global_=False, *,
|
def globals(self):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
if sym.global_])
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return SymInfo([sym for sym in self.syms
|
||||||
|
# note we accept prefixes
|
||||||
|
if s.startswith(section)])
|
||||||
|
|
||||||
|
def collect_syms(obj_path, global_=False, sections=None, *,
|
||||||
objdump_path=OBJDUMP_PATH,
|
objdump_path=OBJDUMP_PATH,
|
||||||
**args):
|
**args):
|
||||||
symbol_pattern = re.compile(
|
symbol_pattern = re.compile(
|
||||||
@@ -259,7 +284,8 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
# u => unique global
|
# u => unique global
|
||||||
# => neither
|
# => neither
|
||||||
# ! => local + global
|
# ! => local + global
|
||||||
if global_ and scope in 'l ':
|
global__ = scope not in 'l '
|
||||||
|
if global_ and not global__:
|
||||||
continue
|
continue
|
||||||
# filter by section? note we accept prefixes
|
# filter by section? note we accept prefixes
|
||||||
if (sections is not None
|
if (sections is not None
|
||||||
@@ -270,7 +296,7 @@ def collect_syms(obj_path, sections=None, global_=False, *,
|
|||||||
if not size:
|
if not size:
|
||||||
continue
|
continue
|
||||||
# note multiple symbols can share a name
|
# note multiple symbols can share a name
|
||||||
syms.append((name, addr, size))
|
syms.append(Sym(name, global__, section, addr, size))
|
||||||
proc.wait()
|
proc.wait()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise sp.CalledProcessError(proc.returncode, proc.args)
|
raise sp.CalledProcessError(proc.returncode, proc.args)
|
||||||
@@ -601,7 +627,9 @@ def collect_job(path, start, stop, syms, lines, *,
|
|||||||
else:
|
else:
|
||||||
# find sym
|
# find sym
|
||||||
sym = syms.get(addr)
|
sym = syms.get(addr)
|
||||||
if sym is None:
|
if sym is not None:
|
||||||
|
sym = sym.name
|
||||||
|
else:
|
||||||
sym = hex(addr)
|
sym = hex(addr)
|
||||||
|
|
||||||
# filter out internal/unknown functions
|
# filter out internal/unknown functions
|
||||||
|
|||||||
Reference in New Issue
Block a user