1#!/usr/bin/env python3
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""This module contains utilities to read ELF files."""
18
19import re
20import subprocess
21
22
23_ELF_CLASS = re.compile(
24    '\\s*Class:\\s*(.*)$')
25_DT_NEEDED = re.compile(
26    '\\s*0x[0-9a-fA-F]+\\s+\\(NEEDED\\)\\s+Shared library: \\[(.*)\\]$')
27_DT_SONAME = re.compile(
28    '\\s*0x[0-9a-fA-F]+\\s+\\(SONAME\\)\\s+Library soname: \\[(.*)\\]$')
29
30
31def readobj(path):
32    """Read ELF bitness, DT_SONAME, and DT_NEEDED."""
33
34    # Read ELF class (32-bit / 64-bit)
35    proc = subprocess.Popen(['readelf', '-h', path], stdout=subprocess.PIPE,
36                            stderr=subprocess.PIPE)
37    stdout = proc.communicate()[0]
38    is_32bit = False
39    for line in stdout.decode('utf-8').splitlines():
40        match = _ELF_CLASS.match(line)
41        if match:
42            if match.group(1) == 'ELF32':
43                is_32bit = True
44
45    # Read DT_SONAME and DT_NEEDED
46    proc = subprocess.Popen(['readelf', '-d', path], stdout=subprocess.PIPE,
47                            stderr=subprocess.PIPE)
48    stdout = proc.communicate()[0]
49    dt_soname = None
50    dt_needed = set()
51    for line in stdout.decode('utf-8').splitlines():
52        match = _DT_NEEDED.match(line)
53        if match:
54            dt_needed.add(match.group(1))
55            continue
56        match = _DT_SONAME.match(line)
57        if match:
58            dt_soname = match.group(1)
59            continue
60
61    return is_32bit, dt_soname, dt_needed
62