summaryrefslogtreecommitdiff
path: root/Tools/c-analyzer/c_symbols
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/c-analyzer/c_symbols')
-rw-r--r--Tools/c-analyzer/c_symbols/__init__.py0
-rw-r--r--Tools/c-analyzer/c_symbols/binary.py157
-rw-r--r--Tools/c-analyzer/c_symbols/info.py51
-rw-r--r--Tools/c-analyzer/c_symbols/resolve.py147
-rw-r--r--Tools/c-analyzer/c_symbols/source.py58
5 files changed, 0 insertions, 413 deletions
diff --git a/Tools/c-analyzer/c_symbols/__init__.py b/Tools/c-analyzer/c_symbols/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
--- a/Tools/c-analyzer/c_symbols/__init__.py
+++ /dev/null
diff --git a/Tools/c-analyzer/c_symbols/binary.py b/Tools/c-analyzer/c_symbols/binary.py
deleted file mode 100644
index e125dbd5b5..0000000000
--- a/Tools/c-analyzer/c_symbols/binary.py
+++ /dev/null
@@ -1,157 +0,0 @@
-import os
-import os.path
-import shutil
-import sys
-
-from c_analyzer_common import util, info
-from . import source
-from .info import Symbol
-
-
-#PYTHON = os.path.join(REPO_ROOT, 'python')
-PYTHON = sys.executable
-
-
-def iter_symbols(binary=PYTHON, dirnames=None, *,
- # Alternately, use look_up_known_symbol()
- # from c_globals.supported.
- find_local_symbol=source.find_symbol,
- _file_exists=os.path.exists,
- _iter_symbols_nm=(lambda b, *a: _iter_symbols_nm(b, *a)),
- ):
- """Yield a Symbol for each symbol found in the binary."""
- if not _file_exists(binary):
- raise Exception('executable missing (need to build it first?)')
-
- if find_local_symbol:
- cache = {}
- def find_local_symbol(name, *, _find=find_local_symbol):
- return _find(name, dirnames, _perfilecache=cache)
- else:
- find_local_symbol = None
-
- if os.name == 'nt':
- # XXX Support this.
- raise NotImplementedError
- else:
- yield from _iter_symbols_nm(binary, find_local_symbol)
-
-
-#############################
-# binary format (e.g. ELF)
-
-SPECIAL_SYMBOLS = {
- '__bss_start',
- '__data_start',
- '__dso_handle',
- '_DYNAMIC',
- '_edata',
- '_end',
- '__environ@@GLIBC_2.2.5',
- '_GLOBAL_OFFSET_TABLE_',
- '__JCR_END__',
- '__JCR_LIST__',
- '__TMC_END__',
- }
-
-
-def _is_special_symbol(name):
- if name in SPECIAL_SYMBOLS:
- return True
- if '@@GLIBC' in name:
- return True
- return False
-
-
-#############################
-# "nm"
-
-NM_KINDS = {
- 'b': Symbol.KIND.VARIABLE, # uninitialized
- 'd': Symbol.KIND.VARIABLE, # initialized
- #'g': Symbol.KIND.VARIABLE, # uninitialized
- #'s': Symbol.KIND.VARIABLE, # initialized
- 't': Symbol.KIND.FUNCTION,
- }
-
-
-def _iter_symbols_nm(binary, find_local_symbol=None,
- *,
- _which=shutil.which,
- _run=util.run_cmd,
- ):
- nm = _which('nm')
- if not nm:
- raise NotImplementedError
- argv = [nm,
- '--line-numbers',
- binary,
- ]
- try:
- output = _run(argv)
- except Exception:
- if nm is None:
- # XXX Use dumpbin.exe /SYMBOLS on Windows.
- raise NotImplementedError
- raise
- for line in output.splitlines():
- (name, kind, external, filename, funcname, vartype,
- ) = _parse_nm_line(line,
- _find_local_symbol=find_local_symbol,
- )
- if kind != Symbol.KIND.VARIABLE:
- continue
- elif _is_special_symbol(name):
- continue
- assert vartype is None
- yield Symbol(
- id=(filename, funcname, name),
- kind=kind,
- external=external,
- )
-
-
-def _parse_nm_line(line, *, _find_local_symbol=None):
- _origline = line
- _, _, line = line.partition(' ') # strip off the address
- line = line.strip()
-
- kind, _, line = line.partition(' ')
- line = line.strip()
- external = kind.isupper()
- kind = NM_KINDS.get(kind.lower(), Symbol.KIND.OTHER)
-
- name, _, filename = line.partition('\t')
- name = name.strip()
- if filename:
- filename = os.path.relpath(filename.partition(':')[0])
- else:
- filename = info.UNKNOWN
-
- vartype = None
- name, islocal = _parse_nm_name(name, kind)
- if islocal:
- funcname = info.UNKNOWN
- if _find_local_symbol is not None:
- filename, funcname, vartype = _find_local_symbol(name)
- filename = filename or info.UNKNOWN
- funcname = funcname or info.UNKNOWN
- else:
- funcname = None
- # XXX fine filename and vartype?
- return name, kind, external, filename, funcname, vartype
-
-
-def _parse_nm_name(name, kind):
- if kind != Symbol.KIND.VARIABLE:
- return name, None
- if _is_special_symbol(name):
- return name, None
-
- actual, sep, digits = name.partition('.')
- if not sep:
- return name, False
-
- if not digits.isdigit():
- raise Exception(f'got bogus name {name}')
- return actual, True
diff --git a/Tools/c-analyzer/c_symbols/info.py b/Tools/c-analyzer/c_symbols/info.py
deleted file mode 100644
index f6ed52c8f0..0000000000
--- a/Tools/c-analyzer/c_symbols/info.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from collections import namedtuple
-
-from c_analyzer_common.info import ID
-from c_analyzer_common.util import classonly, _NTBase
-
-
-class Symbol(_NTBase, namedtuple('Symbol', 'id kind external')):
- """Info for a single compilation symbol."""
-
- __slots__ = ()
-
- class KIND:
- VARIABLE = 'variable'
- FUNCTION = 'function'
- OTHER = 'other'
-
- @classonly
- def from_name(cls, name, filename=None, kind=KIND.VARIABLE, external=None):
- """Return a new symbol based on the given name."""
- id = ID(filename, None, name)
- return cls(id, kind, external)
-
- def __new__(cls, id, kind=KIND.VARIABLE, external=None):
- self = super().__new__(
- cls,
- id=ID.from_raw(id),
- kind=str(kind) if kind else None,
- external=bool(external) if external is not None else None,
- )
- return self
-
- def __hash__(self):
- return hash(self.id)
-
- def __getattr__(self, name):
- return getattr(self.id, name)
-
- def validate(self):
- """Fail if the object is invalid (i.e. init with bad data)."""
- if not self.id:
- raise TypeError('missing id')
- else:
- self.id.validate()
-
- if not self.kind:
- raise TypeError('missing kind')
- elif self.kind not in vars(self.KIND).values():
- raise ValueError(f'unsupported kind {self.kind}')
-
- if self.external is None:
- raise TypeError('missing external')
diff --git a/Tools/c-analyzer/c_symbols/resolve.py b/Tools/c-analyzer/c_symbols/resolve.py
deleted file mode 100644
index 56210cefeb..0000000000
--- a/Tools/c-analyzer/c_symbols/resolve.py
+++ /dev/null
@@ -1,147 +0,0 @@
-import os.path
-
-from c_analyzer_common import files
-from c_analyzer_common.info import UNKNOWN
-from c_parser import declarations, info
-from .info import Symbol
-from .source import _find_symbol
-
-
-# XXX need tests:
-# * look_up_known_symbol()
-# * symbol_from_source()
-# * get_resolver()
-# * symbols_to_variables()
-
-def look_up_known_symbol(symbol, knownvars, *,
- match_files=(lambda f1, f2: f1 == f2),
- ):
- """Return the known variable matching the given symbol.
-
- "knownvars" is a mapping of common.ID to parser.Variable.
-
- "match_files" is used to verify if two filenames point to
- the same file.
- """
- if not knownvars:
- return None
-
- if symbol.funcname == UNKNOWN:
- if not symbol.filename or symbol.filename == UNKNOWN:
- for varid in knownvars:
- if not varid.funcname:
- continue
- if varid.name == symbol.name:
- return knownvars[varid]
- else:
- return None
- else:
- for varid in knownvars:
- if not varid.funcname:
- continue
- if not match_files(varid.filename, symbol.filename):
- continue
- if varid.name == symbol.name:
- return knownvars[varid]
- else:
- return None
- elif not symbol.filename or symbol.filename == UNKNOWN:
- raise NotImplementedError
- else:
- return knownvars.get(symbol.id)
-
-
-def find_in_source(symbol, dirnames, *,
- _perfilecache={},
- _find_symbol=_find_symbol,
- _iter_files=files.iter_files_by_suffix,
- ):
- """Return the Variable matching the given Symbol.
-
- If there is no match then return None.
- """
- if symbol.filename and symbol.filename != UNKNOWN:
- filenames = [symbol.filename]
- else:
- filenames = _iter_files(dirnames, ('.c', '.h'))
-
- if symbol.funcname and symbol.funcname != UNKNOWN:
- raise NotImplementedError
-
- (filename, funcname, decl
- ) = _find_symbol(symbol.name, filenames, _perfilecache)
- if filename == UNKNOWN:
- return None
- return info.Variable.from_parts(filename, funcname, symbol.name, decl)
-
-
-def get_resolver(knownvars=None, dirnames=None, *,
- _look_up_known=look_up_known_symbol,
- _from_source=find_in_source,
- ):
- """Return a "resolver" func for the given known vars and dirnames.
-
- The func takes a single Symbol and returns a corresponding Variable.
- If the symbol was located then the variable will be valid, populated
- with the corresponding information. Otherwise None is returned.
- """
- if knownvars:
- knownvars = dict(knownvars) # a copy
- def resolve_known(symbol):
- found = _look_up_known(symbol, knownvars)
- if found is None:
- return None
- elif symbol.funcname == UNKNOWN:
- knownvars.pop(found.id)
- elif not symbol.filename or symbol.filename == UNKNOWN:
- knownvars.pop(found.id)
- return found
- if dirnames:
- def resolve(symbol):
- found = resolve_known(symbol)
- if found is None:
- return None
- #return _from_source(symbol, dirnames)
- else:
- for dirname in dirnames:
- if not dirname.endswith(os.path.sep):
- dirname += os.path.sep
- if found.filename.startswith(dirname):
- break
- else:
- return None
- return found
- else:
- resolve = resolve_known
- elif dirnames:
- def resolve(symbol):
- return _from_source(symbol, dirnames)
- else:
- def resolve(symbol):
- return None
- return resolve
-
-
-def symbols_to_variables(symbols, *,
- resolve=(lambda s: look_up_known_symbol(s, None)),
- ):
- """Yield the variable the matches each given symbol.
-
- Use get_resolver() for a "resolve" func to use.
- """
- for symbol in symbols:
- if isinstance(symbol, info.Variable):
- # XXX validate?
- yield symbol
- continue
- if symbol.kind != Symbol.KIND.VARIABLE:
- continue
- resolved = resolve(symbol)
- if resolved is None:
- #raise NotImplementedError(symbol)
- resolved = info.Variable(
- id=symbol.id,
- storage=UNKNOWN,
- vartype=UNKNOWN,
- )
- yield resolved
diff --git a/Tools/c-analyzer/c_symbols/source.py b/Tools/c-analyzer/c_symbols/source.py
deleted file mode 100644
index a7248104c9..0000000000
--- a/Tools/c-analyzer/c_symbols/source.py
+++ /dev/null
@@ -1,58 +0,0 @@
-from c_analyzer_common import files
-from c_analyzer_common.info import UNKNOWN
-from c_parser import declarations
-
-
-# XXX need tests:
-# * find_symbol()
-
-def find_symbol(name, dirnames, *,
- _perfilecache,
- _iter_files=files.iter_files_by_suffix,
- **kwargs
- ):
- """Return (filename, funcname, vartype) for the matching Symbol."""
- filenames = _iter_files(dirnames, ('.c', '.h'))
- return _find_symbol(name, filenames, _perfilecache, **kwargs)
-
-
-def _get_symbols(filename, *,
- _iter_variables=declarations.iter_variables,
- ):
- """Return the list of Symbols found in the given file."""
- symbols = {}
- for funcname, name, vartype in _iter_variables(filename):
- if not funcname:
- continue
- try:
- instances = symbols[name]
- except KeyError:
- instances = symbols[name] = []
- instances.append((funcname, vartype))
- return symbols
-
-
-def _find_symbol(name, filenames, _perfilecache, *,
- _get_local_symbols=_get_symbols,
- ):
- for filename in filenames:
- try:
- symbols = _perfilecache[filename]
- except KeyError:
- symbols = _perfilecache[filename] = _get_local_symbols(filename)
-
- try:
- instances = symbols[name]
- except KeyError:
- continue
-
- funcname, vartype = instances.pop(0)
- if not instances:
- symbols.pop(name)
- return filename, funcname, vartype
- else:
- return UNKNOWN, UNKNOWN, UNKNOWN
-
-
-def iter_symbols():
- raise NotImplementedError