#!/usr/bin/env python # # Copyright (C) 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # # Dump the contents of the .note.android.ident section, a NOTE section # embedded into Android binaries. See here: # - master: ndk/sources/crt/crtbrand.S # - master: bionic/libc/arch-common/bionic/crtbrand.S # - NDK before r14: development/ndk/platforms/common/src/crtbrand.c # # Note sections can also be dumped with `readelf -n`. # from __future__ import division, print_function import argparse import logging import struct import subprocess import sys SEC_NAME = '.note.android.ident' NDK_RESERVED_SIZE = 64 def logger(): """Returns the module logger.""" return logging.getLogger(__name__) def round_up_to_nearest(val, step): """Round an integer, val, to the next multiple of a positive integer, step.""" return (val + (step - 1)) // step * step class StructParser(object): def __init__(self, buf): self.buf = buf self.pos = 0 @property def remaining(self): return len(self.buf) - self.pos @property def empty(self): return self.remaining == 0 def read(self, read_len): buf = self.buf[self.pos:read_len + self.pos] self.pos += read_len return buf def read_struct(self, fmt, kind): fmt = struct.Struct(fmt) if self.remaining < fmt.size: sys.exit('error: {} was truncated'.format(kind)) return fmt.unpack(self.read(fmt.size)) def iterate_notes(sec_data): sec_data = StructParser(sec_data) while not sec_data.empty: (namesz, descsz, kind) = sec_data.read_struct(' 0: if name[-1:] == b'\0': name = name[:-1] else: logger().warning('note name %s isn\'t NUL-terminated', name) yield name, kind, desc[:descsz] def dump_android_ident_note(note): note = StructParser(note) (android_api,) = note.read_struct('= 2: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig() file_path = args.file_path with open(file_path, "rb") as obj_file: (sec_off, sec_size) = get_section_pos(SEC_NAME, file_path) obj_file.seek(sec_off) sec_data = obj_file.read(sec_size) if len(sec_data) != sec_size: sys.exit('error: could not read {} section'.format(SEC_NAME)) print('----------ABI INFO----------') if len(sec_data) == 0: logger().warning('%s section is empty', SEC_NAME) for (name, kind, desc) in iterate_notes(sec_data): if (name, kind) == (b'Android', 1): dump_android_ident_note(desc) else: logger().warning('unrecognized note (name %s, type %d)', repr(name), kind) if __name__ == '__main__': main()