Merge "check_elf_file: check prebuilts are aligned" into main
This commit is contained in:
commit
26bb2346de
2 changed files with 81 additions and 3 deletions
|
@ -10,6 +10,8 @@
|
||||||
# - LOCAL_BUILT_MODULE
|
# - LOCAL_BUILT_MODULE
|
||||||
# - LOCAL_IS_HOST_MODULE
|
# - LOCAL_IS_HOST_MODULE
|
||||||
# - LOCAL_MODULE_CLASS
|
# - LOCAL_MODULE_CLASS
|
||||||
|
# - TARGET_MAX_PAGE_SIZE_SUPPORTED
|
||||||
|
# - TARGET_NO_BIONIC_PAGE_SIZE_MACRO
|
||||||
# - intermediates
|
# - intermediates
|
||||||
# - my_installed_module_stem
|
# - my_installed_module_stem
|
||||||
# - my_prebuilt_src_file
|
# - my_prebuilt_src_file
|
||||||
|
@ -26,6 +28,15 @@ $(check_elf_files_stamp): PRIVATE_SYSTEM_SHARED_LIBRARIES := $(my_system_shared_
|
||||||
# In addition to $(my_check_elf_file_shared_lib_files), some file paths are
|
# In addition to $(my_check_elf_file_shared_lib_files), some file paths are
|
||||||
# added by `resolve-shared-libs-for-elf-file-check` from `core/main.mk`.
|
# added by `resolve-shared-libs-for-elf-file-check` from `core/main.mk`.
|
||||||
$(check_elf_files_stamp): PRIVATE_SHARED_LIBRARY_FILES := $(my_check_elf_file_shared_lib_files)
|
$(check_elf_files_stamp): PRIVATE_SHARED_LIBRARY_FILES := $(my_check_elf_file_shared_lib_files)
|
||||||
|
# For different page sizes to work, we must support a larger max page size
|
||||||
|
# as well as properly reflect page size at runtime. Limit this check, since many
|
||||||
|
# devices set the max page size (for future proof) than actually use the
|
||||||
|
# larger page size.
|
||||||
|
ifeq ($(strip $(TARGET_NO_BIONIC_PAGE_SIZE_MACRO)),true)
|
||||||
|
$(check_elf_files_stamp): PRIVATE_MAX_PAGE_SIZE_OPT := --max-page-size=$(TARGET_MAX_PAGE_SIZE_SUPPORTED)
|
||||||
|
else
|
||||||
|
$(check_elf_files_stamp): PRIVATE_MAX_PAGE_SIZE_OPT :=
|
||||||
|
endif
|
||||||
$(check_elf_files_stamp): $(my_prebuilt_src_file) $(my_check_elf_file_shared_lib_files) $(CHECK_ELF_FILE) $(LLVM_READOBJ)
|
$(check_elf_files_stamp): $(my_prebuilt_src_file) $(my_check_elf_file_shared_lib_files) $(CHECK_ELF_FILE) $(LLVM_READOBJ)
|
||||||
@echo Check prebuilt ELF binary: $<
|
@echo Check prebuilt ELF binary: $<
|
||||||
$(hide) mkdir -p $(dir $@)
|
$(hide) mkdir -p $(dir $@)
|
||||||
|
@ -33,6 +44,7 @@ $(check_elf_files_stamp): $(my_prebuilt_src_file) $(my_check_elf_file_shared_lib
|
||||||
$(hide) $(CHECK_ELF_FILE) \
|
$(hide) $(CHECK_ELF_FILE) \
|
||||||
--skip-bad-elf-magic \
|
--skip-bad-elf-magic \
|
||||||
--skip-unknown-elf-machine \
|
--skip-unknown-elf-machine \
|
||||||
|
$(PRIVATE_MAX_PAGE_SIZE_OPT) \
|
||||||
$(if $(PRIVATE_SONAME),--soname $(PRIVATE_SONAME)) \
|
$(if $(PRIVATE_SONAME),--soname $(PRIVATE_SONAME)) \
|
||||||
$(foreach l,$(PRIVATE_SHARED_LIBRARY_FILES),--shared-lib $(l)) \
|
$(foreach l,$(PRIVATE_SHARED_LIBRARY_FILES),--shared-lib $(l)) \
|
||||||
$(foreach l,$(PRIVATE_SYSTEM_SHARED_LIBRARIES),--system-shared-lib $(l)) \
|
$(foreach l,$(PRIVATE_SYSTEM_SHARED_LIBRARIES),--system-shared-lib $(l)) \
|
||||||
|
|
|
@ -67,7 +67,7 @@ ELFHeader = collections.namedtuple(
|
||||||
|
|
||||||
ELF = collections.namedtuple(
|
ELF = collections.namedtuple(
|
||||||
'ELF',
|
'ELF',
|
||||||
('dt_soname', 'dt_needed', 'imported', 'exported', 'header'))
|
('alignments', 'dt_soname', 'dt_needed', 'imported', 'exported', 'header'))
|
||||||
|
|
||||||
|
|
||||||
def _get_os_name():
|
def _get_os_name():
|
||||||
|
@ -195,7 +195,8 @@ class ELFParser(object):
|
||||||
@classmethod
|
@classmethod
|
||||||
def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj):
|
def _read_llvm_readobj(cls, elf_file_path, header, llvm_readobj):
|
||||||
"""Run llvm-readobj and parse the output."""
|
"""Run llvm-readobj and parse the output."""
|
||||||
cmd = [llvm_readobj, '--dynamic-table', '--dyn-symbols', elf_file_path]
|
cmd = [llvm_readobj, '--program-headers', '--dynamic-table',
|
||||||
|
'--dyn-symbols', elf_file_path]
|
||||||
out = subprocess.check_output(cmd, text=True)
|
out = subprocess.check_output(cmd, text=True)
|
||||||
lines = out.splitlines()
|
lines = out.splitlines()
|
||||||
return cls._parse_llvm_readobj(elf_file_path, header, lines)
|
return cls._parse_llvm_readobj(elf_file_path, header, lines)
|
||||||
|
@ -205,9 +206,56 @@ class ELFParser(object):
|
||||||
def _parse_llvm_readobj(cls, elf_file_path, header, lines):
|
def _parse_llvm_readobj(cls, elf_file_path, header, lines):
|
||||||
"""Parse the output of llvm-readobj."""
|
"""Parse the output of llvm-readobj."""
|
||||||
lines_it = iter(lines)
|
lines_it = iter(lines)
|
||||||
|
alignments = cls._parse_program_headers(lines_it)
|
||||||
dt_soname, dt_needed = cls._parse_dynamic_table(elf_file_path, lines_it)
|
dt_soname, dt_needed = cls._parse_dynamic_table(elf_file_path, lines_it)
|
||||||
imported, exported = cls._parse_dynamic_symbols(lines_it)
|
imported, exported = cls._parse_dynamic_symbols(lines_it)
|
||||||
return ELF(dt_soname, dt_needed, imported, exported, header)
|
return ELF(alignments, dt_soname, dt_needed, imported, exported, header)
|
||||||
|
|
||||||
|
|
||||||
|
_PROGRAM_HEADERS_START_PATTERN = 'ProgramHeaders ['
|
||||||
|
_PROGRAM_HEADERS_END_PATTERN = ']'
|
||||||
|
_PROGRAM_HEADER_START_PATTERN = 'ProgramHeader {'
|
||||||
|
_PROGRAM_HEADER_TYPE_PATTERN = re.compile('^\\s+Type:\\s+(.*)$')
|
||||||
|
_PROGRAM_HEADER_ALIGN_PATTERN = re.compile('^\\s+Alignment:\\s+(.*)$')
|
||||||
|
_PROGRAM_HEADER_END_PATTERN = '}'
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _parse_program_headers(cls, lines_it):
|
||||||
|
"""Parse the dynamic table section."""
|
||||||
|
alignments = []
|
||||||
|
|
||||||
|
if not cls._find_prefix(cls._PROGRAM_HEADERS_START_PATTERN, lines_it):
|
||||||
|
raise ELFError()
|
||||||
|
|
||||||
|
for line in lines_it:
|
||||||
|
# Parse each program header
|
||||||
|
if line.strip() == cls._PROGRAM_HEADER_START_PATTERN:
|
||||||
|
p_align = None
|
||||||
|
p_type = None
|
||||||
|
for line in lines_it:
|
||||||
|
if line.strip() == cls._PROGRAM_HEADER_END_PATTERN:
|
||||||
|
if not p_align:
|
||||||
|
raise ELFError("Could not parse alignment from program header!")
|
||||||
|
if not p_type:
|
||||||
|
raise ELFError("Could not parse type from program header!")
|
||||||
|
|
||||||
|
if p_type.startswith("PT_LOAD "):
|
||||||
|
alignments.append(int(p_align))
|
||||||
|
break
|
||||||
|
|
||||||
|
match = cls._PROGRAM_HEADER_TYPE_PATTERN.match(line)
|
||||||
|
if match:
|
||||||
|
p_type = match.group(1)
|
||||||
|
|
||||||
|
match = cls._PROGRAM_HEADER_ALIGN_PATTERN.match(line)
|
||||||
|
if match:
|
||||||
|
p_align = match.group(1)
|
||||||
|
|
||||||
|
if line == cls._PROGRAM_HEADERS_END_PATTERN:
|
||||||
|
break
|
||||||
|
|
||||||
|
return alignments
|
||||||
|
|
||||||
|
|
||||||
_DYNAMIC_SECTION_START_PATTERN = 'DynamicSection ['
|
_DYNAMIC_SECTION_START_PATTERN = 'DynamicSection ['
|
||||||
|
@ -434,6 +482,19 @@ class Checker(object):
|
||||||
|
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
|
def check_max_page_size(self, max_page_size):
|
||||||
|
for alignment in self._file_under_test.alignments:
|
||||||
|
if alignment % max_page_size != 0:
|
||||||
|
self._error(f'Load segment has alignment {alignment} but '
|
||||||
|
f'{max_page_size} required.')
|
||||||
|
self._note()
|
||||||
|
self._note('Fix suggestions:')
|
||||||
|
self._note(f' use linker flag "-Wl,-z,max-page-size={max_page_size}" '
|
||||||
|
f'when compiling this lib')
|
||||||
|
|
||||||
|
# TODO: instead of exiting immediately, we may want to collect the
|
||||||
|
# errors from all checks and emit them at once
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _find_symbol(lib, name, version):
|
def _find_symbol(lib, name, version):
|
||||||
|
@ -514,6 +575,8 @@ def _parse_args():
|
||||||
help='Ignore the input file with unknown machine ID')
|
help='Ignore the input file with unknown machine ID')
|
||||||
parser.add_argument('--allow-undefined-symbols', action='store_true',
|
parser.add_argument('--allow-undefined-symbols', action='store_true',
|
||||||
help='Ignore unresolved undefined symbols')
|
help='Ignore unresolved undefined symbols')
|
||||||
|
parser.add_argument('--max-page-size', action='store', type=int,
|
||||||
|
help='Required page size alignment support')
|
||||||
|
|
||||||
# Other options
|
# Other options
|
||||||
parser.add_argument('--llvm-readobj',
|
parser.add_argument('--llvm-readobj',
|
||||||
|
@ -542,6 +605,9 @@ def main():
|
||||||
|
|
||||||
checker.check_dt_needed(args.system_shared_lib)
|
checker.check_dt_needed(args.system_shared_lib)
|
||||||
|
|
||||||
|
if args.max_page_size:
|
||||||
|
checker.check_max_page_size(args.max_page_size)
|
||||||
|
|
||||||
if not args.allow_undefined_symbols:
|
if not args.allow_undefined_symbols:
|
||||||
checker.check_symbols()
|
checker.check_symbols()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue