import pathlib
import elftools.elf.constants import elftools.elf.descriptions import elftools.elf.sections import memdf.name
from elftools.elf.elffile import ELFFile from memdf.collector.util import simplify_source
from memdf.df import DFs, SectionDF, SegmentDF, SymbolDF
from memdf.util.config import Config, ConfigDescription
CONFIG: ConfigDescription = {}
def read_segments(config: Config, ef: ELFFile) -> SegmentDF:
columns = ['type', 'vaddress', 'paddress', 'size', 'flags']
rows = []
for segment in ef.iter_segments():
rows.append([
segment['p_type'],
segment['p_vaddr'], segment['p_paddr'], segment['p_memsz'],
segment['p_flags']
])
return SegmentDF(rows, columns=columns)
def read_sections(config: Config, ef: ELFFile) -> SectionDF:
columns = ['section', 'type', 'address', 'size', 'flags', 'segment']
index = []
rows = []
for i, section in enumerate(ef.iter_sections()):
index.append(i)
segment_number = -1
for j, segment in enumerate(ef.iter_segments()):
if segment.section_in_segment(section):
segment_number = j
break
rows.append([
section.name,
elftools.elf.descriptions.describe_sh_type(section['sh_type']),
section['sh_addr'], section['sh_size'], section['sh_flags'],
segment_number
])
return SectionDF(rows, index=index, columns=columns)
def read_symbols(config: Config, ef: ELFFile, sections: SectionDF) -> SymbolDF:
section_map = dict(sections.section)
section_map.update({
0: memdf.name.UNDEF,
'SHN_UNDEF': memdf.name.UNDEF,
'SHN_ABS': memdf.name.ABS
})
columns = ['symbol', 'address', 'size', 'section', 'type', 'bind']
rows = []
for section_id, section in enumerate(ef.iter_sections()):
if not isinstance(section, elftools.elf.sections.SymbolTableSection):
continue
for symbol_id, symbol in enumerate(section.iter_symbols()):
st_type = elftools.elf.descriptions.describe_symbol_type(
symbol['st_info']['type'])
st_bind = elftools.elf.descriptions.describe_symbol_bind(
symbol['st_info']['bind'])
st_shndx = symbol['st_shndx'] rows.append([
symbol.name, symbol['st_value'], symbol['st_size'], section_map.get(st_shndx,
memdf.name.UNKNOWN), st_type, st_bind, ])
return SymbolDF(rows, columns=columns)
def cu_offset_to_path_map(config: Config, dwarf_info):
prefixes = config.get_re('collect.prefix')
address_map = {}
for compilation_unit in dwarf_info.iter_CUs():
path = pathlib.Path(compilation_unit.get_top_DIE().get_full_path())
source = simplify_source(str(path.resolve()), prefixes)
address_map[compilation_unit.cu_offset] = source
return address_map
def read_file(config: Config, filename: str, method: str = None) -> DFs:
with open(filename, 'rb') as fp:
ef = ELFFile(fp)
segments = read_segments(config, ef)
sections = read_sections(config, ef)
symbols = read_symbols(config, ef, sections)
if config['args.need_cu']:
dwarf_info = ef.get_dwarf_info()
aranges = dwarf_info.get_aranges()
m = cu_offset_to_path_map(config, dwarf_info)
symbols['cu'] = symbols['address'].apply(lambda a: m.get(
aranges.cu_offset_at_addr(a), '')).astype('string')
if config['args.tag_inputs']:
symbols['input'] = filename
return {
SegmentDF.name: segments,
SectionDF.name: sections,
SymbolDF.name: symbols
}