summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/build/extract_partition.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/build/extract_partition.py')
-rwxr-xr-xthird_party/libwebrtc/build/extract_partition.py174
1 files changed, 174 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/extract_partition.py b/third_party/libwebrtc/build/extract_partition.py
new file mode 100755
index 0000000000..8b79a065d7
--- /dev/null
+++ b/third_party/libwebrtc/build/extract_partition.py
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Extracts an LLD partition from an ELF file."""
+
+import argparse
+import hashlib
+import math
+import os
+import struct
+import subprocess
+import sys
+import tempfile
+
+
+def _ComputeNewBuildId(old_build_id, file_path):
+ """
+ Computes the new build-id from old build-id and file_path.
+
+ Args:
+ old_build_id: Original build-id in bytearray.
+ file_path: Path to output ELF file.
+
+ Returns:
+ New build id with the same length as |old_build_id|.
+ """
+ m = hashlib.sha256()
+ m.update(old_build_id)
+ m.update(os.path.basename(file_path).encode('utf-8'))
+ hash_bytes = m.digest()
+ # In case build_id is longer than hash computed, repeat the hash
+ # to the desired length first.
+ id_size = len(old_build_id)
+ hash_size = len(hash_bytes)
+ return (hash_bytes * (id_size // hash_size + 1))[:id_size]
+
+
+def _ExtractPartition(objcopy, input_elf, output_elf, partition):
+ """
+ Extracts a partition from an ELF file.
+
+ For partitions other than main partition, we need to rewrite
+ the .note.gnu.build-id section so that the build-id remains
+ unique.
+
+ Note:
+ - `objcopy` does not modify build-id when partitioning the
+ combined ELF file by default.
+ - The new build-id is calculated as hash of original build-id
+ and partitioned ELF file name.
+
+ Args:
+ objcopy: Path to objcopy binary.
+ input_elf: Path to input ELF file.
+ output_elf: Path to output ELF file.
+ partition: Partition to extract from combined ELF file. None when
+ extracting main partition.
+ """
+ if not partition: # main partition
+ # We do not overwrite build-id on main partition to allow the expected
+ # partition build ids to be synthesized given a libchrome.so binary,
+ # if necessary.
+ subprocess.check_call(
+ [objcopy, '--extract-main-partition', input_elf, output_elf])
+ return
+
+ # partitioned libs
+ build_id_section = '.note.gnu.build-id'
+
+ with tempfile.TemporaryDirectory() as tempdir:
+ temp_elf = os.path.join(tempdir, 'obj_without_id.so')
+ old_build_id_file = os.path.join(tempdir, 'old_build_id')
+ new_build_id_file = os.path.join(tempdir, 'new_build_id')
+
+ # Dump out build-id section and remove original build-id section from
+ # ELF file.
+ subprocess.check_call([
+ objcopy,
+ '--extract-partition',
+ partition,
+ # Note: Not using '--update-section' here as it is not supported
+ # by llvm-objcopy.
+ '--remove-section',
+ build_id_section,
+ '--dump-section',
+ '{}={}'.format(build_id_section, old_build_id_file),
+ input_elf,
+ temp_elf,
+ ])
+
+ with open(old_build_id_file, 'rb') as f:
+ note_content = f.read()
+
+ # .note section has following format according to <elf/external.h>
+ # typedef struct {
+ # unsigned char namesz[4]; /* Size of entry's owner string */
+ # unsigned char descsz[4]; /* Size of the note descriptor */
+ # unsigned char type[4]; /* Interpretation of the descriptor */
+ # char name[1]; /* Start of the name+desc data */
+ # } Elf_External_Note;
+ # `build-id` rewrite is only required on Android platform,
+ # where we have partitioned lib.
+ # Android platform uses little-endian.
+ # <: little-endian
+ # 4x: Skip 4 bytes
+ # L: unsigned long, 4 bytes
+ descsz, = struct.Struct('<4xL').unpack_from(note_content)
+ prefix = note_content[:-descsz]
+ build_id = note_content[-descsz:]
+
+ with open(new_build_id_file, 'wb') as f:
+ f.write(prefix + _ComputeNewBuildId(build_id, output_elf))
+
+ # Write back the new build-id section.
+ subprocess.check_call([
+ objcopy,
+ '--add-section',
+ '{}={}'.format(build_id_section, new_build_id_file),
+ # Add alloc section flag, or else the section will be removed by
+ # objcopy --strip-all when generating unstripped lib file.
+ '--set-section-flags',
+ '{}={}'.format(build_id_section, 'alloc'),
+ temp_elf,
+ output_elf,
+ ])
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--partition',
+ help='Name of partition if not the main partition',
+ metavar='PART')
+ parser.add_argument(
+ '--objcopy',
+ required=True,
+ help='Path to llvm-objcopy binary',
+ metavar='FILE')
+ parser.add_argument(
+ '--unstripped-output',
+ required=True,
+ help='Unstripped output file',
+ metavar='FILE')
+ parser.add_argument(
+ '--stripped-output',
+ required=True,
+ help='Stripped output file',
+ metavar='FILE')
+ parser.add_argument('--dwp', help='Path to dwp binary', metavar='FILE')
+ parser.add_argument('input', help='Input file')
+ args = parser.parse_args()
+
+ _ExtractPartition(args.objcopy, args.input, args.unstripped_output,
+ args.partition)
+ subprocess.check_call([
+ args.objcopy,
+ '--strip-all',
+ args.unstripped_output,
+ args.stripped_output,
+ ])
+
+ if args.dwp:
+ dwp_args = [
+ args.dwp, '-e', args.unstripped_output, '-o',
+ args.unstripped_output + '.dwp'
+ ]
+ # Suppress output here because it doesn't seem to be useful. The most
+ # common error is a segfault, which will happen if files are missing.
+ subprocess.check_output(dwp_args, stderr=subprocess.STDOUT)
+
+
+if __name__ == '__main__':
+ sys.exit(main())