Roll chromium_revision 95336cb92b..191d55580e (557816:557824)

Change log: 95336cb92b..191d55580e
Full diff: 95336cb92b..191d55580e

Roll chromium third_party 4e16929f46..3a8f2a9e1e
Change log: 4e16929f46..3a8f2a9e1e

Changed dependencies:
* src/tools: c44a3f5eca..f524a53b81
DEPS diff: 95336cb92b..191d55580e/DEPS

No update to Clang.

TBR=titovartem@google.com,
BUG=None
CQ_INCLUDE_TRYBOTS=master.internal.tryserver.corp.webrtc:linux_internal

Change-Id: Ic9c4a62b050383646e9fcf5cc07a5653c14ac06e
Reviewed-on: https://webrtc-review.googlesource.com/76120
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Commit-Queue: Artem Titov <titovartem@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23205}
This commit is contained in:
Artem Titov
2018-05-11 12:21:36 +02:00
committed by Artem Titov
parent a04d140666
commit 739351d476
3839 changed files with 1777993 additions and 8 deletions

6
DEPS
View File

@ -10,7 +10,7 @@ vars = {
'checkout_configuration': 'default',
'checkout_instrumented_libraries': 'checkout_linux and checkout_configuration == "default"',
'webrtc_git': 'https://webrtc.googlesource.com',
'chromium_revision': '95336cb92b1337d4ad5d2a7fcc7409ec25b4a8ee',
'chromium_revision': '191d55580e6b2dda1206b51de589e18e7865b863',
'boringssl_git': 'https://boringssl.googlesource.com',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling swarming_client
@ -43,7 +43,7 @@ vars = {
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Chromium third_party
# and whatever else without interference from each other.
'chromium_third_party_revision': '4e16929f465a47942875a80da0140bfaa59e99fb',
'chromium_third_party_revision': '3a8f2a9e1ee29a040102635292f92d82bab94990',
}
deps = {
# TODO(kjellander): Move this to be Android-only once the libevent dependency
@ -175,7 +175,7 @@ deps = {
'src/third_party/yasm/source/patched-yasm':
Var('chromium_git') + '/chromium/deps/yasm/patched-yasm.git' + '@' + 'b98114e18d8b9b84586b10d24353ab8616d4c5fc',
'src/tools':
Var('chromium_git') + '/chromium/src/tools' + '@' + 'c44a3f5eca9ea560d23230b73afdb8e31bb16611',
Var('chromium_git') + '/chromium/src/tools' + '@' + 'f524a53b8173e5c367d5d6e740d036d8df9347bd',
'src/tools/gyp':
Var('chromium_git') + '/external/gyp.git' + '@' + 'd61a9397e668fa9843c4aa7da9e79460fe590bfb',
'src/tools/swarming_client':

View File

@ -417,8 +417,8 @@ def _ReportErrorFileAndLineNumber(filename, line_num):
def CheckNoStreamUsageIsAdded(input_api, output_api,
error_formatter=_ReportErrorFileAndLineNumber,
source_file_filter):
source_file_filter,
error_formatter=_ReportErrorFileAndLineNumber):
"""Make sure that no more dependencies on stringstream are added."""
error_msg = ('Usage of <sstream>, <istream> and <ostream> in WebRTC is '
'deprecated.\n'
@ -813,7 +813,7 @@ def CommonChecks(input_api, output_api):
results.extend(CheckNewlineAtTheEndOfProtoFiles(
input_api, output_api, source_file_filter=non_third_party_sources))
results.extend(CheckNoStreamUsageIsAdded(
input_api, output_api, source_file_filter=non_third_party_sources))
input_api, output_api, non_third_party_sources))
return results

View File

@ -86,7 +86,8 @@ class CheckNewlineAtTheEndOfProtoFilesTest(unittest.TestCase):
self._GenerateProtoWithoutNewlineAtTheEnd()
self.input_api.files = [MockFile(self.proto_file_path)]
errors = PRESUBMIT.CheckNewlineAtTheEndOfProtoFiles(self.input_api,
self.output_api)
self.output_api,
lambda x: True)
self.assertEqual(1, len(errors))
self.assertEqual(
'File %s must end with exactly one newline.' % self.proto_file_path,
@ -96,7 +97,8 @@ class CheckNewlineAtTheEndOfProtoFilesTest(unittest.TestCase):
self._GenerateProtoWithNewlineAtTheEnd()
self.input_api.files = [MockFile(self.proto_file_path)]
errors = PRESUBMIT.CheckNewlineAtTheEndOfProtoFiles(self.input_api,
self.output_api)
self.output_api,
lambda x: True)
self.assertEqual(0, len(errors))
def _GenerateProtoWithNewlineAtTheEnd(self):

68
third_party/BUILD.gn vendored Normal file
View File

@ -0,0 +1,68 @@
# Copyright 2014 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.
import("//build/config/freetype/freetype.gni")
import("//third_party/harfbuzz-ng/harfbuzz.gni")
import("//third_party/libjpeg.gni")
assert(!is_ios, "This is not used on iOS, don't drag it in unintentionally")
config("system_libjpeg_config") {
libs = [ "jpeg" ]
defines = [ "USE_SYSTEM_LIBJPEG" ]
}
config("libjpeg_turbo_config") {
defines = [ "USE_LIBJPEG_TURBO=1" ]
}
# This is a meta target that forwards to the system's libjpeg,
# third_party/libjpeg, or third_party/libjpeg_turbo depending on the build args
# declared in this file.
group("jpeg") {
if (use_system_libjpeg) {
public_configs = [ ":system_libjpeg_config" ]
} else if (use_libjpeg_turbo) {
public_deps = [
"//third_party/libjpeg_turbo:libjpeg",
]
public_configs = [ ":libjpeg_turbo_config" ]
} else {
public_deps = [
"//third_party/libjpeg:libjpeg",
]
}
}
# This is a meta target that forwards include paths only to the system's
# libjpeg, third_party/libjpeg, or third_party/libjpeg_turbo depending on the
# build args declared in this file. This is needed, rarely, for targets that
# need to reference libjpeg without explicitly building it.
group("jpeg_includes") {
if (use_system_libjpeg) {
public_configs = [ ":system_libjpeg_config" ]
} else if (use_libjpeg_turbo) {
public_configs = [ "//third_party/libjpeg_turbo:libjpeg_config" ]
} else {
public_configs = [ "//third_party/libjpeg:libjpeg_config" ]
}
}
# FreeType and HarfBuzz libraries are dependent on each other. This component
# will depend on the appropriate source sets or export the system packages
# for both FreeType and HarfBuzz.
component("freetype_harfbuzz") {
public_configs = []
public_deps = []
if (use_system_freetype) {
public_configs += [ "//build/linux:freetype_from_pkgconfig" ]
} else {
public_deps += [ "//third_party/freetype:freetype_source" ]
}
if (use_system_harfbuzz) {
public_configs += [ "//third_party/harfbuzz-ng:harfbuzz_from_pkgconfig" ]
} else {
public_deps += [ "//third_party/harfbuzz-ng:harfbuzz_source" ]
}
}

11
third_party/DEPS vendored Normal file
View File

@ -0,0 +1,11 @@
# Undo everything in the include_rules section of src/DEPS.
include_rules = [
'-base',
'-build',
'-ipc',
'-library_loaders',
'-testing',
'-third_party/icu/source/common/unicode',
'-third_party/icu/source/i18n/unicode',
'-url',
]

141
third_party/PRESUBMIT.py vendored Normal file
View File

@ -0,0 +1,141 @@
# Copyright (c) 2011 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.
ANDROID_WHITELISTED_LICENSES = [
'A(pple )?PSL 2(\.0)?',
'Apache( Version)? 2(\.0)?',
'(New )?([23]-Clause )?BSD( [23]-Clause)?( with advertising clause)?',
'L?GPL ?v?2(\.[01])?( or later)?',
'MIT(/X11)?(-like)?',
'MPL 1\.1 ?/ ?GPL 2(\.0)? ?/ ?LGPL 2\.1',
'MPL 2(\.0)?',
'Microsoft Limited Public License',
'Microsoft Permissive License',
'Public Domain',
'Python',
'SGI Free Software License B',
'University of Illinois\/NCSA Open Source',
'X11',
]
def LicenseIsCompatibleWithAndroid(input_api, license):
regex = '^(%s)$' % '|'.join(ANDROID_WHITELISTED_LICENSES)
tokens = \
[x.strip() for x in input_api.re.split(' and |,', license) if len(x) > 0]
has_compatible_license = False
for token in tokens:
if input_api.re.match(regex, token, input_api.re.IGNORECASE):
has_compatible_license = True
break
return has_compatible_license
def _CheckThirdPartyReadmesUpdated(input_api, output_api):
"""
Checks to make sure that README.chromium files are properly updated
when dependencies in third_party are modified.
"""
readmes = []
files = []
errors = []
for f in input_api.AffectedFiles():
local_path = f.LocalPath()
if input_api.os_path.dirname(local_path) == 'third_party':
continue
if (local_path.startswith('third_party' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'WebKit' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'blink' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'mojo' + input_api.os_path.sep) and
not local_path.startswith('third_party' + input_api.os_path.sep +
'boringssl' + input_api.os_path.sep)):
files.append(f)
if local_path.endswith("README.chromium"):
readmes.append(f)
if files and not readmes:
errors.append(output_api.PresubmitPromptWarning(
'When updating or adding third party code the appropriate\n'
'\'README.chromium\' file should also be updated with the correct\n'
'version and package information.', files))
if not readmes:
return errors
name_pattern = input_api.re.compile(
r'^Name: [a-zA-Z0-9_\-\. \(\)]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
shortname_pattern = input_api.re.compile(
r'^Short Name: [a-zA-Z0-9_\-\.]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
version_pattern = input_api.re.compile(
r'^Version: [a-zA-Z0-9_\-\.:]+\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
release_pattern = input_api.re.compile(
r'^Security Critical: (yes|no)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
license_pattern = input_api.re.compile(
r'^License: (.+)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
license_android_compatible_pattern = input_api.re.compile(
r'^License Android Compatible: (yes|no)\r?$',
input_api.re.IGNORECASE | input_api.re.MULTILINE)
for f in readmes:
if 'D' in f.Action():
_IgnoreIfDeleting(input_api, output_api, f, errors)
continue
contents = input_api.ReadFile(f)
if (not shortname_pattern.search(contents)
and not name_pattern.search(contents)):
errors.append(output_api.PresubmitError(
'Third party README files should contain either a \'Short Name\' or\n'
'a \'Name\' which is the name under which the package is\n'
'distributed. Check README.chromium.template for details.',
[f]))
if not version_pattern.search(contents):
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'Version\' field.\n'
'If the package is not versioned or the version is not known\n'
'list the version as \'unknown\'.\n'
'Check README.chromium.template for details.',
[f]))
if not release_pattern.search(contents):
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'Security Critical\'\n'
'field. This field specifies whether the package is built with\n'
'Chromium. Check README.chromium.template for details.',
[f]))
license_match = license_pattern.search(contents)
if not license_match:
errors.append(output_api.PresubmitError(
'Third party README files should contain a \'License\' field.\n'
'This field specifies the license used by the package. Check\n'
'README.chromium.template for details.',
[f]))
elif not LicenseIsCompatibleWithAndroid(input_api, license_match.group(1)) \
and not license_android_compatible_pattern.search(contents):
errors.append(output_api.PresubmitPromptWarning(
'Cannot determine whether specified license is compatible with\n' +
'the Android licensing requirements. Please check that the license\n' +
'name is spelled according to third_party/PRESUBMIT.py. Please see\n' +
'README.chromium.template for details.',
[f]))
return errors
def _IgnoreIfDeleting(input_api, output_api, affected_file, errors):
third_party_dir = input_api.os_path.dirname(affected_file.LocalPath())
for f in input_api.AffectedFiles():
if f.LocalPath().startswith(third_party_dir):
if 'D' not in f.Action():
errors.append(output_api.PresubmitError(
'Third party README should only be removed when the whole\n'
'directory is being removed.\n', [f, affected_file]))
def CheckChangeOnUpload(input_api, output_api):
results = []
results.extend(_CheckThirdPartyReadmesUpdated(input_api, output_api))
return results

14
third_party/README.chromium vendored Normal file
View File

@ -0,0 +1,14 @@
The third_party directory contains sources from other projects.
Code in third_party must document the license under which the source is being
used. If the source itself does not include a license header or file, create
an entry in this file that refers to reliable documentation of the project's
license terms on the web (and add a note pointing here in the README file in
that directory).
When adding a new directory, or updating a directory to a version which has
a different license from before, please add chromium-third-party@google.com
as a reviewer on the change.
<Include table of license information here, once it is available>

16
third_party/README.chromium.template vendored Normal file
View File

@ -0,0 +1,16 @@
Name: Descriptive name of the package
Short Name: Name the package is distributed under (ex. libxml, openssl, etc)
URL: The URL where the package lives
Version: A searchable version number for the package (if the package does not version or is versioned by date or revision this field should be "0" and the revision, or date should be enumerated in the appropriate field)
Date: (OPTIONAL if version is supplied) The date that the package was updated
Revision: (OPTIONAL if version is supplied) The current revision of the package
License: The license under which the package is distributed. Standard forms are only accepted, eg MIT/X11/BSD/Apache 2.0/GPL/LGPL. See ANDROID_WHITELISTED_LICENSES in PRESUBMIT.py for allowed patterns.
License File: (OPTIONAL) File that contains a copy of the package's license. Use the special value NOT_SHIPPED to indicate that the package is not included in the shipped product, so its license does not need to be included in about:credits and no license file is required.
Security Critical: Either yes or no depending on whether this package is shipped in releases. For example openssl is critical where cygwin is not.
License Android Compatible: (OPTIONAL) Whether the package uses a license compatible with Android. Required only if the package is compatible and the 'License' field uses a non-standard value.
Description:
A short description of what the package is and is used for.
Local Modifications:
Enumerate any changes that have been made locally to the package from the shipping version listed above.

View File

@ -0,0 +1,10 @@
# Copyright 2016 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.
import("//build/config/android/rules.gni")
java_prebuilt("accessibility_test_framework_java") {
testonly = true
jar_path = "lib/accessibility-test-framework.jar"
}

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,3 @@
jbudorick@chromium.org
mikecase@chromium.org
yolandyan@chromium.org

View File

@ -0,0 +1,10 @@
Name: Accessibility-Test-Framework-for-Android
URL: https://github.com/google/Accessibility-Test-Framework-for-Android
Version: 2.1
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: no
Description:
Library that contains accessibility-related checks for Android View and
AccessibilityNodeInfo objects.
Local Modifications: None

View File

@ -0,0 +1,10 @@
# Copyright 2017 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.
# To create CIPD package run the following command.
# cipd create --pkg-def cipd.yaml -tag version:$(cat version.txt)
package: chromium/third_party/accessibility-test-framework
description: accessibility-test-framework Java library
data:
- file: lib/accessibility-test-framework.jar

83
third_party/android_platform/BUILD.gn vendored Normal file
View File

@ -0,0 +1,83 @@
# Copyright 2015 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.
import("//testing/test.gni")
import("config.gni")
if (current_toolchain == host_toolchain) {
source_set("android_lib_relocation_packer") {
deps = [
"//third_party/elfutils:libelf",
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
sources = [
"bionic/tools/relocation_packer/src/debug.cc",
"bionic/tools/relocation_packer/src/debug.h",
"bionic/tools/relocation_packer/src/delta_encoder.cc",
"bionic/tools/relocation_packer/src/delta_encoder.h",
"bionic/tools/relocation_packer/src/elf_file.cc",
"bionic/tools/relocation_packer/src/elf_file.h",
"bionic/tools/relocation_packer/src/elf_traits.h",
"bionic/tools/relocation_packer/src/packer.cc",
"bionic/tools/relocation_packer/src/packer.h",
"bionic/tools/relocation_packer/src/sleb128.cc",
"bionic/tools/relocation_packer/src/sleb128.h",
]
}
executable("android_relocation_packer") {
deps = [
":android_lib_relocation_packer",
"//build/config:exe_and_shlib_deps",
"//third_party/elfutils:libelf",
]
sources = [
"bionic/tools/relocation_packer/src/main.cc",
"bionic/tools/relocation_packer/src/nativehelper/ScopedFd.h",
]
}
copy("copy_android_relocation_packer_test_data") {
sources = [
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm32_packed.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_arm64_packed.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_ia32_packed.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_mips32_packed.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64.so",
"bionic/tools/relocation_packer/test_data/elf_file_unittest_relocs_x64_packed.so",
]
outputs = [
"$root_out_dir/{{source_file_part}}",
]
}
test("android_relocation_packer_unittests") {
deps = [
":android_lib_relocation_packer",
":copy_android_relocation_packer_test_data",
"//testing/gtest",
]
sources = [
"bionic/tools/relocation_packer/src/debug_unittest.cc",
"bionic/tools/relocation_packer/src/delta_encoder_unittest.cc",
"bionic/tools/relocation_packer/src/elf_file_unittest.cc",
"bionic/tools/relocation_packer/src/packer_unittest.cc",
"bionic/tools/relocation_packer/src/run_all_unittests.cc",
"bionic/tools/relocation_packer/src/sleb128_unittest.cc",
]
}
}
if (is_android) {
import("//build/config/android/rules.gni")
wrapper_script("stack_wrapper") {
target = "//third_party/android_platform/development/scripts/stack"
}
}

202
third_party/android_platform/LICENSE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

4
third_party/android_platform/OWNERS vendored Normal file
View File

@ -0,0 +1,4 @@
agrieve@chromium.org
rmcilroy@chromium.org
# COMPONENT: Infra>Client>Android

View File

@ -0,0 +1,64 @@
Name: Android Platform engineering tools
Short Name: android platform development
URL: https://android.googlesource.com/platform/development
Version: unknown
Date: 2014/05/02
Revision: 1b10ec4
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: no
Description:
Android Platform engineering tools, specifically:
1. stack symbolization scripts
2. A ported copy of the Android relocation packing tool source, along with the
files required to build it in the chromium tree.
3. IntelliJ formatting settings.
Taken from commit: 622d3d4c5b3bee50fd335f3282d9e9d64ae0f5f7
Local Modifications:
Only picked the few components useful to Chromium (as listed above).
The scripts have been modified to better suit Chromium development. Changes
include, but are not limited to, the following:
Added memoization of addr2line and objdump.
Added option to change the amount of symbolization done.
Updated output directories to be set by environment variable or --flags
When calling addr2line, check the symbol is a file that looks like it contains
symbols.
Added support for parsing LOG(FATAL) and DCHECK errors and their
stack traces, as emitted by src/base/debug/stack_trace_android.cc
Added support for finding symbols when library is loaded directly from the APK.
Changed the toolchain to remove references to 4.6 toolchains.
Added support for arch=x64 as an alias to arch=x86_64
Added debug logging and --verbose parameter.
Used fast ELF symbolizer for symbols.py and tombstones
Used multiprocessing to pre-process logcat before symbolizing it
Added code address adjustment for the debuggerd output from pre-M Android
where relocations are packed.
Added code to capture java stderr for better handling of native->java crashes.
Fixed invalid using decl in logging header debug.h
Only attempt to symbolize with ELF libraries.
Changed the stack script to use llvm symbolizer instead of addr2line,
objdump, etc, since llvm symbolizer is more efficient in finding
function names, line numbers etc.
Speedup symbolization by avoiding unnecessary APK manifest extraction loops.
Android relocation packing tool details:
Copy sources from AOSP bionic/tools/relocation_packer
Remove scripts that regenerate golden test data (not relevant here)
Create a nativehelper/ScopedFd.h to satisfy inclusion from main.cc
Create gyp build
Create gn build (currently packer only; no unit tests)
List of bionic changes currently included:
Refresh: https://android-review.googlesource.com/#/c/143878/
Refresh: https://android-review.googlesource.com/#/c/147620/
https://android-review.googlesource.com/#/c/147745/
https://android-review.googlesource.com/#/c/148073/
Refresh: https://android-review.googlesource.com/#/c/151901/
https://android-review.googlesource.com/#/c/149300/
https://android-review.googlesource.com/#/c/148822/
https://android-review.googlesource.com/#/c/148492/
https://android-review.googlesource.com/#/c/148175/

View File

@ -0,0 +1,103 @@
#
# Copyright (C) 2015 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.
#
common_cppflags := -Wall -Wextra -Wunused -Werror -Wold-style-cast
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
src/debug.cc \
src/delta_encoder.cc \
src/elf_file.cc \
src/packer.cc \
src/sleb128.cc \
LOCAL_STATIC_LIBRARIES := libelf
LOCAL_C_INCLUDES := external/elfutils/src/libelf
LOCAL_MODULE := lib_relocation_packer
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := src/main.cc
LOCAL_STATIC_LIBRARIES := lib_relocation_packer libelf
# Statically linking libc++ to make it work from prebuilts
LOCAL_CXX_STL := libc++_static
LOCAL_C_INCLUDES := external/elfutils/src/libelf libnativehelper/include
LOCAL_MODULE := relocation_packer
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
src/debug_unittest.cc \
src/delta_encoder_unittest.cc \
src/elf_file_unittest.cc \
src/sleb128_unittest.cc \
src/packer_unittest.cc \
LOCAL_STATIC_LIBRARIES := lib_relocation_packer libelf
LOCAL_C_INCLUDES := external/elfutils/src/libelf
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_MODULE := relocation_packer_unit_tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_HOST_NATIVE_TEST)
# $(1) library name
define copy-test-library
include $(CLEAR_VARS)
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE := $(1)
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_PATH := $(HOST_OUT_EXECUTABLES)
LOCAL_STRIP_MODULE := false
LOCAL_SRC_FILES := test_data/$(1)
include $(BUILD_PREBUILT)
endef
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm32_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_arm64_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_ia32_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_x64.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_x64_packed.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32.so))
$(eval $(call copy-test-library,elf_file_unittest_relocs_mips32_packed.so))

View File

@ -0,0 +1,27 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,5 @@
include_rules = [
'+gtest',
'+nativehelper',
'+testing',
]

View File

@ -0,0 +1,55 @@
// Copyright 2014 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.
#include "debug.h"
#include <stdlib.h>
#include <iostream>
#include <string>
namespace relocation_packer {
// Construct a new message logger. Prints if level is less than or equal to
// the level set with SetVerbose() and predicate is true.
Logger::Logger(Severity severity, int level, bool predicate) {
severity_ = severity;
level_ = level;
predicate_ = predicate;
}
// On destruction, flush and print the strings accumulated. Abort if FATAL.
Logger::~Logger() {
if (predicate_) {
if (level_ <= max_level_) {
std::ostream* log = severity_ == INFO ? info_stream_ : error_stream_;
std::string tag;
switch (severity_) {
case INFO: tag = "INFO"; break;
case WARNING: tag = "WARNING"; break;
case ERROR: tag = "ERROR"; break;
case FATAL: tag = "FATAL"; break;
}
stream_.flush();
*log << tag << ": " << stream_.str() << std::endl;
}
if (severity_ == FATAL)
abort();
}
}
// Reset to initial state.
void Logger::Reset() {
max_level_ = -1;
info_stream_ = &std::cout;
error_stream_ = &std::cerr;
}
// Verbosity. Not thread-safe.
int Logger::max_level_ = -1;
// Logging streams. Not thread-safe.
std::ostream* Logger::info_stream_ = &std::cout;
std::ostream* Logger::error_stream_ = &std::cerr;
} // namespace relocation_packer

View File

@ -0,0 +1,118 @@
// Copyright 2014 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.
// Logging and checks. Avoids a dependency on base.
//
// LOG(tag) prints messages. Tags are INFO, WARNING, ERROR and FATAL.
// INFO prints to stdout, the others to stderr. FATAL aborts after printing.
//
// LOG_IF(tag, predicate) logs if predicate evaluates to true, else silent.
//
// VLOG(level) logs INFO messages where level is less than or equal to the
// verbosity level set with SetVerbose().
//
// VLOG_IF(level, predicate) logs INFO if predicate evaluates to true,
// else silent.
//
// CHECK(predicate) logs a FATAL error if predicate is false.
// NOTREACHED() always aborts.
// Log streams can be changed with SetStreams(). Logging is not thread-safe.
//
#ifndef TOOLS_RELOCATION_PACKER_SRC_DEBUG_H_
#define TOOLS_RELOCATION_PACKER_SRC_DEBUG_H_
#include <limits.h>
#include <ostream>
#include <sstream>
namespace relocation_packer {
class Logger {
public:
enum Severity {INFO = 0, WARNING, ERROR, FATAL};
// Construct a new message logger. Prints if level is less than or
// equal to the level set with SetVerbose() and predicate is true.
// |severity| is an enumerated severity.
// |level| is the verbosity level.
// |predicate| controls if the logger prints or is silent.
Logger(Severity severity, int level, bool predicate);
// On destruction, flush and print the strings accumulated in stream_.
~Logger();
// Return the stream for this logger.
std::ostream& GetStream() { return stream_; }
// Set verbosity level. Messages with a level less than or equal to
// this level are printed, others are discarded. Static, not thread-safe.
static void SetVerbose(int level) { max_level_ = level; }
// Set info and error logging streams. Static, not thread-safe.
static void SetStreams(std::ostream* info_stream,
std::ostream* error_stream) {
info_stream_ = info_stream;
error_stream_ = error_stream;
}
// Reset to initial state.
static void Reset();
private:
// Message severity, verbosity level, and predicate.
Severity severity_;
int level_;
bool predicate_;
// String stream, accumulates message text.
std::ostringstream stream_;
// Verbosity for INFO messages. Not thread-safe.
static int max_level_;
// Logging streams. Not thread-safe.
static std::ostream* info_stream_;
static std::ostream* error_stream_;
};
} // namespace relocation_packer
// Make logging severities visible globally.
typedef relocation_packer::Logger::Severity LogSeverity;
// LOG(severity) prints a message with the given severity, and aborts if
// severity is FATAL. LOG_IF(severity, predicate) does the same but only if
// predicate is true. INT_MIN is guaranteed to be less than or equal to
// any verbosity level.
#define LOG(severity) \
(relocation_packer::Logger(relocation_packer::Logger::severity, INT_MIN, \
true) \
.GetStream())
#define LOG_IF(severity, predicate) \
(relocation_packer::Logger(relocation_packer::Logger::severity, INT_MIN, \
(predicate)) \
.GetStream())
// VLOG(level) prints its message as INFO if level is less than or equal to
// the current verbosity level.
#define VLOG(level) \
(relocation_packer::Logger(relocation_packer::Logger::INFO, (level), true) \
.GetStream())
#define VLOG_IF(level, predicate) \
(relocation_packer::Logger(relocation_packer::Logger::INFO, (level), \
(predicate)) \
.GetStream())
// CHECK(predicate) fails with a FATAL log message if predicate is false.
#define CHECK(predicate) (LOG_IF(FATAL, !(predicate)) \
<< __FILE__ << ":" << __LINE__ << ": " \
<< __FUNCTION__ << ": CHECK '" #predicate "' failed")
// NOTREACHED() always fails with a FATAL log message.
#define NOTREACHED(_) (LOG(FATAL) \
<< __FILE__ << ":" << __LINE__ << ": " \
<< __FUNCTION__ << ": NOTREACHED() hit")
#endif // TOOLS_RELOCATION_PACKER_SRC_DEBUG_H_

View File

@ -0,0 +1,122 @@
// Copyright 2014 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.
#include "debug.h"
#include <sstream>
#include "gtest/gtest.h"
namespace relocation_packer {
TEST(Debug, Log) {
Logger::Reset();
std::ostringstream info;
std::ostringstream error;
Logger::SetStreams(&info, &error);
LOG(INFO) << "INFO log message";
LOG(WARNING) << "WARNING log message";
LOG(ERROR) << "ERROR log message";
EXPECT_EQ("INFO: INFO log message\n", info.str());
EXPECT_EQ("WARNING: WARNING log message\n"
"ERROR: ERROR log message\n", error.str());
Logger::Reset();
}
TEST(Debug, LogIf) {
Logger::Reset();
std::ostringstream info;
std::ostringstream error;
Logger::SetStreams(&info, &error);
LOG_IF(INFO, true) << "INFO log message";
LOG_IF(INFO, false) << "INFO log message, SHOULD NOT PRINT";
LOG_IF(WARNING, true) << "WARNING log message";
LOG_IF(WARNING, false) << "WARNING log message, SHOULD NOT PRINT";
LOG_IF(ERROR, true) << "ERROR log message";
LOG_IF(ERROR, false) << "ERROR log message, SHOULD NOT PRINT";
LOG_IF(FATAL, false) << "FATAL log message, SHOULD NOT PRINT";
EXPECT_EQ("INFO: INFO log message\n", info.str());
EXPECT_EQ("WARNING: WARNING log message\n"
"ERROR: ERROR log message\n", error.str());
Logger::Reset();
}
TEST(Debug, Vlog) {
Logger::Reset();
std::ostringstream info;
std::ostringstream error;
Logger::SetStreams(&info, &error);
VLOG(0) << "VLOG 0 INFO log message, SHOULD NOT PRINT";
VLOG(1) << "VLOG 1 INFO log message, SHOULD NOT PRINT";
VLOG(2) << "VLOG 2 INFO log message, SHOULD NOT PRINT";
EXPECT_EQ("", info.str());
EXPECT_EQ("", error.str());
Logger::SetVerbose(1);
VLOG(0) << "VLOG 0 INFO log message";
VLOG(1) << "VLOG 1 INFO log message";
VLOG(2) << "VLOG 2 INFO log message, SHOULD NOT PRINT";
EXPECT_EQ("INFO: VLOG 0 INFO log message\n"
"INFO: VLOG 1 INFO log message\n", info.str());
EXPECT_EQ("", error.str());
Logger::Reset();
}
TEST(Debug, VlogIf) {
Logger::Reset();
std::ostringstream info;
std::ostringstream error;
Logger::SetStreams(&info, &error);
VLOG_IF(0, true) << "VLOG 0 INFO log message, SHOULD NOT PRINT";
VLOG_IF(1, true) << "VLOG 1 INFO log message, SHOULD NOT PRINT";
VLOG_IF(2, true) << "VLOG 2 INFO log message, SHOULD NOT PRINT";
EXPECT_EQ("", info.str());
EXPECT_EQ("", error.str());
Logger::SetVerbose(1);
VLOG_IF(0, true) << "VLOG 0 INFO log message";
VLOG_IF(0, false) << "VLOG 0 INFO log message, SHOULD NOT PRINT";
VLOG_IF(1, true) << "VLOG 1 INFO log message";
VLOG_IF(1, false) << "VLOG 1 INFO log message, SHOULD NOT PRINT";
VLOG_IF(2, true) << "VLOG 2 INFO log message, SHOULD NOT PRINT";
VLOG_IF(2, false) << "VLOG 2 INFO log message, SHOULD NOT PRINT";
EXPECT_EQ("INFO: VLOG 0 INFO log message\n"
"INFO: VLOG 1 INFO log message\n", info.str());
EXPECT_EQ("", error.str());
Logger::Reset();
}
TEST(DebugDeathTest, Fatal) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
Logger::Reset();
EXPECT_DEATH(LOG(FATAL) << "FATAL log message", "FATAL: FATAL log message");
EXPECT_DEATH(
LOG_IF(FATAL, true) << "FATAL log message", "FATAL: FATAL log message");
}
TEST(DebugDeathTest, Check) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
Logger::Reset();
CHECK(0 == 0);
EXPECT_DEATH(CHECK(0 == 1), "FATAL: .*:.*: .*: CHECK '0 == 1' failed");
}
TEST(DebugDeathTest, NotReached) {
::testing::FLAGS_gtest_death_test_style = "threadsafe";
Logger::Reset();
EXPECT_DEATH(NOTREACHED(), "FATAL: .*:.*: .*: NOTREACHED\\(\\) hit");
}
} // namespace relocation_packer

View File

@ -0,0 +1,307 @@
// Copyright 2014 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.
#include "delta_encoder.h"
#include <vector>
#include "debug.h"
static constexpr uint32_t RELOCATION_GROUPED_BY_INFO_FLAG = 1;
static constexpr uint32_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 2;
static constexpr uint32_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 4;
static constexpr uint32_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 8;
static bool is_relocation_grouped_by_info(uint64_t flags) {
return (flags & RELOCATION_GROUPED_BY_INFO_FLAG) != 0;
}
static bool is_relocation_grouped_by_offset_delta(uint64_t flags) {
return (flags & RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG) != 0;
}
static bool is_relocation_grouped_by_addend(uint64_t flags) {
return (flags & RELOCATION_GROUPED_BY_ADDEND_FLAG) != 0;
}
static bool is_relocation_group_has_addend(uint64_t flags) {
return (flags & RELOCATION_GROUP_HAS_ADDEND_FLAG) != 0;
}
namespace relocation_packer {
// Encode relocations into a delta encoded (packed) representation.
template <typename ELF>
void RelocationDeltaCodec<ELF>::Encode(const std::vector<ElfRela>& relocations,
std::vector<ElfAddr>* packed) {
if (relocations.size() == 0)
return;
// Start with the relocation count, then append groups
// TODO(dimitry): we might want to move it to DT_ANDROID_RELCOUNT section
packed->push_back(static_cast<ElfAddr>(relocations.size()));
// lets write starting offset (offset of the first reloc - first delta)
ElfAddr start_offset = relocations.size() > 1 ?
relocations[0].r_offset - (relocations[1].r_offset - relocations[0].r_offset) :
relocations[0].r_offset;
packed->push_back(start_offset);
// this one is used to calculate delta
ElfAddr previous_addend = 0;
ElfAddr previous_offset = start_offset;
for (size_t group_start = 0; group_start < relocations.size(); ) {
ElfAddr group_flags = 0;
ElfAddr group_offset_delta = 0;
ElfAddr group_addend = 0;
ElfAddr group_info = 0;
ElfAddr group_size = 0;
DetectGroup(relocations, group_start, previous_offset, &group_size, &group_flags,
&group_offset_delta, &group_info, &group_addend);
// write the group header
packed->push_back(group_size);
packed->push_back(group_flags);
if (is_relocation_grouped_by_offset_delta(group_flags)) {
packed->push_back(group_offset_delta);
}
if (is_relocation_grouped_by_info(group_flags)) {
packed->push_back(group_info);
}
if (is_relocation_group_has_addend(group_flags) &&
is_relocation_grouped_by_addend(group_flags)) {
packed->push_back(group_addend - previous_addend);
previous_addend = group_addend;
}
for (size_t i = 0; i < static_cast<size_t>(group_size); ++i) {
CHECK((group_start + i) < relocations.size());
const ElfRela* relocation = &relocations[group_start + i];
if (!is_relocation_grouped_by_offset_delta(group_flags)) {
packed->push_back(relocation->r_offset - previous_offset);
}
previous_offset = relocation->r_offset;
if (!is_relocation_grouped_by_info(group_flags)) {
packed->push_back(relocation->r_info);
}
if (is_relocation_group_has_addend(group_flags) &&
!is_relocation_grouped_by_addend(group_flags)) {
packed->push_back(relocation->r_addend - previous_addend);
previous_addend = relocation->r_addend;
}
}
// If the relocation group does not have an addend - reset it to 0
// to simplify addend computation for the group following this one.
if (!is_relocation_group_has_addend(group_flags)) {
previous_addend = 0;
}
group_start += group_size;
}
}
// Decode relocations from a delta encoded (packed) representation.
template <typename ELF>
void RelocationDeltaCodec<ELF>::Decode(const std::vector<ElfAddr>& packed,
std::vector<ElfRela>* relocations) {
if (packed.size() < 5) {
return;
}
size_t ndx = 0;
ElfAddr current_count = 0;
ElfAddr total_count = packed[ndx++];
ElfAddr offset = packed[ndx++];
ElfAddr info = 0;
ElfAddr addend = 0;
while(current_count < total_count) {
// read group
ElfAddr group_size = packed[ndx++];
ElfAddr group_flags = packed[ndx++];
ElfAddr group_offset_delta = 0;
if (is_relocation_grouped_by_offset_delta(group_flags)) {
group_offset_delta = packed[ndx++];
}
if (is_relocation_grouped_by_info(group_flags)) {
info = packed[ndx++];
}
if (is_relocation_group_has_addend(group_flags) &&
is_relocation_grouped_by_addend(group_flags)) {
addend += packed[ndx++];
}
// now read not grouped info
for (ElfAddr i = 0; i<group_size; ++i) {
if (is_relocation_grouped_by_offset_delta(group_flags)) {
offset += group_offset_delta;
} else {
offset += packed[ndx++];
}
if (!is_relocation_grouped_by_info(group_flags)) {
info = packed[ndx++];
}
if (is_relocation_group_has_addend(group_flags) &&
!is_relocation_grouped_by_addend(group_flags)) {
addend += packed[ndx++];
}
ElfRela reloc;
reloc.r_offset = offset;
reloc.r_info = info;
reloc.r_addend = is_relocation_group_has_addend(group_flags) ? addend : 0;
relocations->push_back(reloc);
}
if (!is_relocation_group_has_addend(group_flags)) {
addend = 0;
}
current_count += group_size;
}
}
// This function detects a way to group reloc_one and reloc_two, sets up group_flags
// and initializes values for corresponding group_ fields. For example if relocations
// can be grouped by r_info the function will set group_info variable.
template <typename ELF>
void RelocationDeltaCodec<ELF>::DetectGroupFields(const ElfRela& reloc_one,
const ElfRela& reloc_two,
ElfAddr current_offset_delta,
ElfAddr* group_flags,
ElfAddr* group_offset_delta,
ElfAddr* group_info,
ElfAddr* group_addend) {
*group_flags = 0;
const ElfAddr offset_delta = static_cast<ElfAddr>(reloc_two.r_offset) -
static_cast<ElfAddr>(reloc_one.r_offset);
if (offset_delta == current_offset_delta) {
*group_flags |= RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG;
if (group_offset_delta != nullptr) {
*group_offset_delta = current_offset_delta;
}
}
if (reloc_one.r_info == reloc_two.r_info) {
*group_flags |= RELOCATION_GROUPED_BY_INFO_FLAG;
if (group_info != nullptr) {
*group_info = reloc_one.r_info;
}
}
if (reloc_one.r_addend != 0 || reloc_two.r_addend != 0) {
*group_flags |= RELOCATION_GROUP_HAS_ADDEND_FLAG;
if (reloc_one.r_addend == reloc_two.r_addend) {
*group_flags |= RELOCATION_GROUPED_BY_ADDEND_FLAG;
if (group_addend != nullptr) {
*group_addend = reloc_one.r_addend;
}
}
}
}
// This function is used to detect if there is better group available
// during RelocationDeltaCodec<ELF>::DetectGroup processing.
// Current implementation prefers having groups without addend (== zero addend)
// to any other groups field with the ratio 3:1. This is because addend tends
// to be more unevenly distributed than other fields.
static uint32_t group_weight(uint64_t flags) {
uint32_t weight = 0;
if (!is_relocation_group_has_addend(flags)) {
weight += 3;
} else if (is_relocation_grouped_by_addend(flags)) {
weight += 1;
}
if (is_relocation_grouped_by_offset_delta(flags)) {
weight += 1;
}
if (is_relocation_grouped_by_info(flags)) {
weight += 1;
}
return weight;
}
template <typename ELF>
void RelocationDeltaCodec<ELF>::DetectGroup(const std::vector<ElfRela>& relocations,
size_t group_starts_with, ElfAddr previous_offset,
ElfAddr* group_size, ElfAddr* group_flags,
ElfAddr* group_offset_delta, ElfAddr* group_info,
ElfAddr* group_addend) {
CHECK(group_starts_with < relocations.size());
CHECK(group_flags != nullptr);
const ElfRela& reloc_one = relocations[group_starts_with++];
if (group_starts_with == relocations.size()) {
*group_flags = reloc_one.r_addend == 0 ? 0 : RELOCATION_GROUP_HAS_ADDEND_FLAG;
*group_size = 1;
return;
}
const ElfAddr offset_delta = reloc_one.r_offset - previous_offset;
// detect group_flags
DetectGroupFields(reloc_one, relocations[group_starts_with], offset_delta, group_flags,
group_offset_delta, group_info, group_addend);
if (group_starts_with + 1 == relocations.size()) {
*group_size = 2;
return;
}
ElfAddr cnt = 1;
for (size_t i = group_starts_with; i < relocations.size() - 1; ++i) {
ElfAddr candidate_flags;
// check if next group (reloc_current; reloc_next) has better grouped_by flags
DetectGroupFields(relocations[i], relocations[i+1], offset_delta, &candidate_flags,
nullptr, nullptr, nullptr);
if (group_weight(*group_flags) < group_weight(candidate_flags)) {
break;
}
cnt++;
if (candidate_flags != *group_flags) {
break;
}
if (i + 1 == relocations.size() - 1) { // last one
cnt++;
}
}
// if as a result of checking candidates we ended up with cnt == 1
// reset flags to the default state
if (cnt == 1) {
*group_flags = reloc_one.r_addend == 0 ? 0 : RELOCATION_GROUP_HAS_ADDEND_FLAG;
}
*group_size = cnt;
}
template class RelocationDeltaCodec<ELF32_traits>;
template class RelocationDeltaCodec<ELF64_traits>;
} // namespace relocation_packer

View File

@ -0,0 +1,132 @@
// Copyright 2014 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.
// Delta encode and decode REL/RELA section of elf file.
//
// The encoded data format is sequence of elements of ElfAddr type (unsigned long):
//
// [00] relocation_count - the total count of relocations
// [01] initial r_offset - this is initial r_offset for the
// relocation table.
// followed by group structures:
// [02] group
// ...
// [nn] group
// the generalized format of the group is (! - always present ? - depends on group_flags):
// --------------
// ! group_size
// ! group_flags
// ? group_r_offset_delta when RELOCATION_GROUPED_BY_OFFSET_DELTA flag is set
// ? group_r_info when RELOCATION_GROUPED_BY_INFO flag is set
// ? group_r_addend_group_delta when RELOCATION_GROUP_HAS_ADDEND and RELOCATION_GROUPED_BY_ADDEND
// flag is set
//
// The group description is followed by individual relocations.
// please note that there is a case when individual relocation
// section could be empty - that is if every field ends up grouped.
//
// The format for individual relocations section is:
// ? r_offset_delta - when RELOCATION_GROUPED_BY_OFFSET_DELTA is not set
// ? r_info - when RELOCATION_GROUPED_BY_INFO flag is not set
// ? r_addend_delta - RELOCATION_GROUP_HAS_ADDEND is set and RELOCATION_GROUPED_BY_ADDEND is not set
//
// For example lets pack the following relocations:
//
// Relocation section '.rela.dyn' at offset 0xbf58 contains 939 entries:
// Offset Info Type Symbol's Value Symbol's Name + Addend
// 00000000000a2178 0000000000000403 R_AARCH64_RELATIVE 177a8
// 00000000000a2180 0000000000000403 R_AARCH64_RELATIVE 177cc
// 00000000000a2188 0000000000000403 R_AARCH64_RELATIVE 177e0
// 00000000000a2190 0000000000000403 R_AARCH64_RELATIVE 177f4
// 00000000000a2198 0000000000000403 R_AARCH64_RELATIVE 17804
// 00000000000a21a0 0000000000000403 R_AARCH64_RELATIVE 17818
// 00000000000a21a8 0000000000000403 R_AARCH64_RELATIVE 1782c
// 00000000000a21b0 0000000000000403 R_AARCH64_RELATIVE 17840
// 00000000000a21b8 0000000000000403 R_AARCH64_RELATIVE 17854
// 00000000000a21c0 0000000000000403 R_AARCH64_RELATIVE 17868
// 00000000000a21c8 0000000000000403 R_AARCH64_RELATIVE 1787c
// 00000000000a21d0 0000000000000403 R_AARCH64_RELATIVE 17890
// 00000000000a21d8 0000000000000403 R_AARCH64_RELATIVE 178a4
// 00000000000a21e8 0000000000000403 R_AARCH64_RELATIVE 178b8
//
// The header is going to be
// [00] 14 <- count
// [01] 0x00000000000a2170 <- initial relocation (first relocation - delta,
// the delta is 8 in this case)
// -- starting the first and only group
// [03] 14 <- group size
// [03] 0xb <- flags RELOCATION_GROUP_HAS_ADDEND | RELOCATION_GROUPED_BY_OFFSET_DELTA
// | RELOCATION_GROUPED_BY_INFO
// [04] 8 <- offset delta
// [05] 0x403 <- r_info
// -- end of group definition, starting list of r_addend deltas
// [06] 0x177a8
// [07] 0x24 = 177cc - 177a8
// [08] 0x14 = 177e0 - 177cc
// [09] 0x14 = 177f4 - 177e0
// [10] 0x10 = 17804 - 177f4
// [11] 0x14 = 17818 - 17804
// [12] 0x14 = 1782c - 17818
// [13] 0x14 = 17840 - 1782c
// [14] 0x14 = 17854 - 17840
// [15] 0x14 = 17868 - 17854
// [16] 0x14 = 1787c - 17868
// [17] 0x14 = 17890 - 1787c
// [18] 0x14 = 178a4 - 17890
// [19] 0x14 = 178b8 - 178a4
// -- the end.
// TODO (dimitry): consider using r_addend_group_delta in the way we use group offset delta, it can
// save us more bytes...
// The input ends when sum(group_size) == relocation_count
#ifndef TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_
#define TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_
#include <vector>
#include "elf.h"
#include "elf_traits.h"
namespace relocation_packer {
// A RelocationDeltaCodec packs vectors of relative relocations with
// addends into more compact forms, and unpacks them to reproduce the
// pre-packed data.
template <typename ELF>
class RelocationDeltaCodec {
public:
typedef typename ELF::Addr ElfAddr;
typedef typename ELF::Rela ElfRela;
// Encode relocations with addends into a more compact form.
// |relocations| is a vector of relative relocation with addend structs.
// |packed| is the vector of packed words into which relocations are packed.
static void Encode(const std::vector<ElfRela>& relocations,
std::vector<ElfAddr>* packed);
// Decode relative relocations with addends from their more compact form.
// |packed| is the vector of packed relocations.
// |relocations| is a vector of unpacked relative relocations.
static void Decode(const std::vector<ElfAddr>& packed,
std::vector<ElfRela>* relocations);
private:
static void DetectGroup(const std::vector<ElfRela>& relocations,
size_t group_starts_with, ElfAddr previous_offset,
ElfAddr* group_size, ElfAddr* group_flags,
ElfAddr* group_offset_delta, ElfAddr* group_info,
ElfAddr* group_addend);
static void DetectGroupFields(const ElfRela& reloc_one, const ElfRela& reloc_two,
ElfAddr current_offset_delta, ElfAddr* group_flags,
ElfAddr* group_offset_delta, ElfAddr* group_info,
ElfAddr* group_addend);
};
} // namespace relocation_packer
#endif // TOOLS_RELOCATION_PACKER_SRC_DELTA_ENCODER_H_

View File

@ -0,0 +1,223 @@
// Copyright 2014 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.
#include "delta_encoder.h"
#include <vector>
#include "elf.h"
#include "gtest/gtest.h"
namespace {
template <typename T>
void AddRelocation(uint32_t addr,
uint32_t info,
int32_t addend,
std::vector<T>* relocations) {
T relocation;
relocation.r_offset = addr;
relocation.r_info = info;
relocation.r_addend = addend;
relocations->push_back(relocation);
}
template <typename T>
bool CheckRelocation(uint32_t addr,
uint32_t info,
int32_t addend,
const T& relocation) {
return relocation.r_offset == addr &&
relocation.r_info == info &&
relocation.r_addend == addend;
}
} // namespace
namespace relocation_packer {
template <typename ELF>
static void encode() {
std::vector<typename ELF::Rela> relocations;
std::vector<typename ELF::Addr> packed;
RelocationDeltaCodec<ELF> codec;
codec.Encode(relocations, &packed);
ASSERT_EQ(0U, packed.size());
// Initial relocation.
AddRelocation(0xf00d0000, 11U, 10000, &relocations);
codec.Encode(relocations, &packed);
// size of reloc table, size of group, flags, 3 fields, zero
EXPECT_EQ(7U, packed.size());
// One pair present.
size_t ndx = 0;
EXPECT_EQ(1U, packed[ndx++]);
EXPECT_EQ(0xf00d0000, packed[ndx++]);
EXPECT_EQ(1U, packed[ndx++]); // group_size
EXPECT_EQ(8U, packed[ndx++]); // flags
// Delta from the neutral element is zero
EXPECT_EQ(0U, packed[ndx++]); // offset_delta
EXPECT_EQ(11U, packed[ndx++]); // info
EXPECT_EQ(10000U, packed[ndx++]); // addend_delta
// Add a second relocation, 4 byte offset delta, 12 byte addend delta.
// same info
AddRelocation(0xf00d0004, 11U, 10012, &relocations);
packed.clear();
codec.Encode(relocations, &packed);
ndx = 0;
EXPECT_EQ(8U, packed.size());
EXPECT_EQ(2U, packed[ndx++]); // relocs count
EXPECT_EQ(0xf00cfffc, packed[ndx++]); // initial offset
EXPECT_EQ(2U, packed[ndx++]); // group count
EXPECT_EQ(11U, packed[ndx++]); // flags
EXPECT_EQ(4U, packed[ndx++]); // group offset delta
EXPECT_EQ(11U, packed[ndx++]); // info
EXPECT_EQ(10000U, packed[ndx++]); // addend delta
EXPECT_EQ(12U, packed[ndx++]); // addend delta
// Add a third relocation, 4 byte offset delta, 12 byte addend delta.
// different info
AddRelocation(0xf00d0008, 41U, 10024, &relocations);
// Add three more relocations, 8 byte offset deltas, -24 byte addend deltas.
AddRelocation(0xf00d0010, 42U, 10000, &relocations);
AddRelocation(0xf00d0018, 42U, 9976, &relocations);
AddRelocation(0xf00d0020, 42U, 9952, &relocations);
AddRelocation(0xf00d2028, 1042U, 0, &relocations);
AddRelocation(0xf00d2030, 3442U, 0, &relocations);
packed.clear();
codec.Encode(relocations, &packed);
ndx = 0;
EXPECT_EQ(26U, packed.size());
// Total number of relocs
EXPECT_EQ(8U, packed[ndx++]);
EXPECT_EQ(0xf00cfffc, packed[ndx++]);
// 2 in first group
EXPECT_EQ(2U, packed[ndx++]);
EXPECT_EQ(11U, packed[ndx++]); //flags
EXPECT_EQ(4U, packed[ndx++]); // group offset delta
EXPECT_EQ(11U, packed[ndx++]); // info
// Initial relocation.
EXPECT_EQ(10000U, packed[ndx++]); // addend delta
// Two relocations, 4 byte offset deltas, 12 byte addend deltas.
EXPECT_EQ(12U, packed[ndx++]); // addend delta
// second group has only one reloc
EXPECT_EQ(1U, packed[ndx++]); // count
EXPECT_EQ(8U, packed[ndx++]); // flags
EXPECT_EQ(4U, packed[ndx++]); // offset delta
EXPECT_EQ(41U, packed[ndx++]); // info
EXPECT_EQ(12U, packed[ndx++]); // addend delta
// next - 3 relocs grouped by info
EXPECT_EQ(3U, packed[ndx++]); // count
EXPECT_EQ(11U, packed[ndx++]); // flags
EXPECT_EQ(8U, packed[ndx++]); // group offset delta
EXPECT_EQ(42U, packed[ndx++]); // info
// Three relocations, 8 byte offset deltas, -24 byte addend deltas.
EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]);
EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]);
EXPECT_EQ(static_cast<typename ELF::Addr>(-24), packed[ndx++]);
// and last - 2 relocations without addend
EXPECT_EQ(2U, packed[ndx++]);
EXPECT_EQ(0U, packed[ndx++]); // flags
// offset_deltas and r_infos for next 2 relocations
EXPECT_EQ(0x2008U, packed[ndx++]); // offset delta
EXPECT_EQ(1042U, packed[ndx++]); // r_info
EXPECT_EQ(0x8U, packed[ndx++]); // offset delta
EXPECT_EQ(3442U, packed[ndx++]); // r_info
EXPECT_EQ(packed.size(), ndx);
}
TEST(Delta, Encode32) {
encode<ELF32_traits>();
}
TEST(Delta, Encode64) {
encode<ELF64_traits>();
}
template <typename ELF>
static void decode() {
std::vector<typename ELF::Addr> packed;
std::vector<typename ELF::Rela> relocations;
RelocationDeltaCodec<ELF> codec;
codec.Decode(packed, &relocations);
EXPECT_EQ(0U, relocations.size());
// Six pairs.
packed.push_back(6U); // count
packed.push_back(0xc0ddfffc); // base offset
packed.push_back(3U); // group count
packed.push_back(11U); // flags
packed.push_back(4U); // offset delta
packed.push_back(11U); // info
// Initial relocation.
packed.push_back(10000U);
// Two relocations, 4 byte offset deltas, 12 byte addend deltas.
packed.push_back(12U); // addend
packed.push_back(12U); // addend
// Three relocations, 8 byte offset deltas, -24 byte addend deltas.
packed.push_back(1U); // group count
packed.push_back(9U); // flags
packed.push_back(11U); // info
packed.push_back(8U);
packed.push_back(static_cast<typename ELF::Addr>(-24));
// next group with 2 relocs
packed.push_back(2U); // group count
packed.push_back(11U); // flags
packed.push_back(8U); // offset
packed.push_back(42U); // info
packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend
packed.push_back(static_cast<typename ELF::Addr>(-24)); // addend
relocations.clear();
codec.Decode(packed, &relocations);
EXPECT_EQ(6U, relocations.size());
// Initial relocation.
EXPECT_TRUE(CheckRelocation(0xc0de0000, 11U, 10000, relocations[0]));
// Two relocations, 4 byte offset deltas, 12 byte addend deltas.
EXPECT_TRUE(CheckRelocation(0xc0de0004, 11U, 10012, relocations[1]));
EXPECT_TRUE(CheckRelocation(0xc0de0008, 11U, 10024, relocations[2]));
// Three relocations, 8 byte offset deltas, -24 byte addend deltas.
EXPECT_TRUE(CheckRelocation(0xc0de0010, 11U, 10000, relocations[3]));
EXPECT_TRUE(CheckRelocation(0xc0de0018, 42U, 9976, relocations[4]));
EXPECT_TRUE(CheckRelocation(0xc0de0020, 42U, 9952, relocations[5]));
}
TEST(Delta, Decode32) {
decode<ELF32_traits>();
}
TEST(Delta, Decode64) {
decode<ELF64_traits>();
}
// TODO (dimitry): add more tests (fix by 19 January 2038 03:14:07 UTC)
// TODO (dimtiry): 1. Incorrect packed array for decode
// TODO (dimtiry): 2. Try to catch situation where it is likely to get series of groups with size 1
} // namespace relocation_packer

View File

@ -0,0 +1,993 @@
// Copyright 2014 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.
// Implementation notes:
//
// We need to remove a piece from the ELF shared library. However, we also
// want to avoid fixing DWARF cfi data and relative relocation addresses.
// So after packing we shift offets and starting address of the RX segment
// while preserving code/data vaddrs location.
// This requires some fixups for symtab/hash/gnu_hash dynamic section addresses.
#include "elf_file.h"
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <string>
#include <vector>
#include "debug.h"
#include "elf_traits.h"
#include "libelf.h"
#include "packer.h"
namespace relocation_packer {
// Out-of-band dynamic tags used to indicate the offset and size of the
// android packed relocations section.
static constexpr int32_t DT_ANDROID_REL = DT_LOOS + 2;
static constexpr int32_t DT_ANDROID_RELSZ = DT_LOOS + 3;
static constexpr int32_t DT_ANDROID_RELA = DT_LOOS + 4;
static constexpr int32_t DT_ANDROID_RELASZ = DT_LOOS + 5;
static constexpr uint32_t SHT_ANDROID_REL = SHT_LOOS + 1;
static constexpr uint32_t SHT_ANDROID_RELA = SHT_LOOS + 2;
static const size_t kPageSize = 4096;
// Alignment to preserve, in bytes. This must be at least as large as the
// largest d_align and sh_addralign values found in the loaded file.
// Out of caution for RELRO page alignment, we preserve to a complete target
// page. See http://www.airs.com/blog/archives/189.
static const size_t kPreserveAlignment = kPageSize;
// Get section data. Checks that the section has exactly one data entry,
// so that the section size and the data size are the same. True in
// practice for all sections we resize when packing or unpacking. Done
// by ensuring that a call to elf_getdata(section, data) returns NULL as
// the next data entry.
static Elf_Data* GetSectionData(Elf_Scn* section) {
Elf_Data* data = elf_getdata(section, NULL);
CHECK(data && elf_getdata(section, data) == NULL);
return data;
}
// Rewrite section data. Allocates new data and makes it the data element's
// buffer. Relies on program exit to free allocated data.
static void RewriteSectionData(Elf_Scn* section,
const void* section_data,
size_t size) {
Elf_Data* data = GetSectionData(section);
CHECK(size == data->d_size);
uint8_t* area = new uint8_t[size];
memcpy(area, section_data, size);
data->d_buf = area;
}
// Verbose ELF header logging.
template <typename Ehdr>
static void VerboseLogElfHeader(const Ehdr* elf_header) {
VLOG(1) << "e_phoff = " << elf_header->e_phoff;
VLOG(1) << "e_shoff = " << elf_header->e_shoff;
VLOG(1) << "e_ehsize = " << elf_header->e_ehsize;
VLOG(1) << "e_phentsize = " << elf_header->e_phentsize;
VLOG(1) << "e_phnum = " << elf_header->e_phnum;
VLOG(1) << "e_shnum = " << elf_header->e_shnum;
VLOG(1) << "e_shstrndx = " << elf_header->e_shstrndx;
}
// Verbose ELF program header logging.
template <typename Phdr>
static void VerboseLogProgramHeader(size_t program_header_index,
const Phdr* program_header) {
std::string type;
switch (program_header->p_type) {
case PT_NULL: type = "NULL"; break;
case PT_LOAD: type = "LOAD"; break;
case PT_DYNAMIC: type = "DYNAMIC"; break;
case PT_INTERP: type = "INTERP"; break;
case PT_PHDR: type = "PHDR"; break;
case PT_GNU_RELRO: type = "GNU_RELRO"; break;
case PT_GNU_STACK: type = "GNU_STACK"; break;
case PT_ARM_EXIDX: type = "EXIDX"; break;
default: type = "(OTHER)"; break;
}
VLOG(1) << "phdr[" << program_header_index << "] : " << type;
VLOG(1) << " p_offset = " << program_header->p_offset;
VLOG(1) << " p_vaddr = " << program_header->p_vaddr;
VLOG(1) << " p_paddr = " << program_header->p_paddr;
VLOG(1) << " p_filesz = " << program_header->p_filesz;
VLOG(1) << " p_memsz = " << program_header->p_memsz;
VLOG(1) << " p_flags = " << program_header->p_flags;
VLOG(1) << " p_align = " << program_header->p_align;
}
// Verbose ELF section header logging.
template <typename Shdr>
static void VerboseLogSectionHeader(const std::string& section_name,
const Shdr* section_header) {
VLOG(1) << "section " << section_name;
VLOG(1) << " sh_addr = " << section_header->sh_addr;
VLOG(1) << " sh_offset = " << section_header->sh_offset;
VLOG(1) << " sh_size = " << section_header->sh_size;
VLOG(1) << " sh_entsize = " << section_header->sh_entsize;
VLOG(1) << " sh_addralign = " << section_header->sh_addralign;
}
// Verbose ELF section data logging.
static void VerboseLogSectionData(const Elf_Data* data) {
VLOG(1) << " data";
VLOG(1) << " d_buf = " << data->d_buf;
VLOG(1) << " d_off = " << data->d_off;
VLOG(1) << " d_size = " << data->d_size;
VLOG(1) << " d_align = " << data->d_align;
}
// Load the complete ELF file into a memory image in libelf, and identify
// the .rel.dyn or .rela.dyn, .dynamic, and .android.rel.dyn or
// .android.rela.dyn sections. No-op if the ELF file has already been loaded.
template <typename ELF>
bool ElfFile<ELF>::Load() {
if (elf_)
return true;
Elf* elf = elf_begin(fd_, ELF_C_RDWR, NULL);
CHECK(elf);
if (elf_kind(elf) != ELF_K_ELF) {
LOG(ERROR) << "File not in ELF format";
return false;
}
auto elf_header = ELF::getehdr(elf);
if (!elf_header) {
LOG(ERROR) << "Failed to load ELF header: " << elf_errmsg(elf_errno());
return false;
}
if (elf_header->e_type != ET_DYN) {
LOG(ERROR) << "ELF file is not a shared object";
return false;
}
// Require that our endianness matches that of the target, and that both
// are little-endian. Safe for all current build/target combinations.
const int endian = elf_header->e_ident[EI_DATA];
CHECK(endian == ELFDATA2LSB);
CHECK(__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__);
const int file_class = elf_header->e_ident[EI_CLASS];
VLOG(1) << "endian = " << endian << ", file class = " << file_class;
VerboseLogElfHeader(elf_header);
auto elf_program_header = ELF::getphdr(elf);
CHECK(elf_program_header != nullptr);
const typename ELF::Phdr* dynamic_program_header = NULL;
for (size_t i = 0; i < elf_header->e_phnum; ++i) {
auto program_header = &elf_program_header[i];
VerboseLogProgramHeader(i, program_header);
if (program_header->p_type == PT_DYNAMIC) {
CHECK(dynamic_program_header == NULL);
dynamic_program_header = program_header;
}
}
CHECK(dynamic_program_header != nullptr);
size_t string_index;
elf_getshdrstrndx(elf, &string_index);
// Notes of the dynamic relocations, packed relocations, and .dynamic
// sections. Found while iterating sections, and later stored in class
// attributes.
Elf_Scn* found_relocations_section = nullptr;
Elf_Scn* found_dynamic_section = nullptr;
// Notes of relocation section types seen. We require one or the other of
// these; both is unsupported.
bool has_rel_relocations = false;
bool has_rela_relocations = false;
bool has_android_relocations = false;
Elf_Scn* section = NULL;
while ((section = elf_nextscn(elf, section)) != nullptr) {
auto section_header = ELF::getshdr(section);
std::string name = elf_strptr(elf, string_index, section_header->sh_name);
VerboseLogSectionHeader(name, section_header);
// Note relocation section types.
if (section_header->sh_type == SHT_REL || section_header->sh_type == SHT_ANDROID_REL) {
has_rel_relocations = true;
}
if (section_header->sh_type == SHT_RELA || section_header->sh_type == SHT_ANDROID_RELA) {
has_rela_relocations = true;
}
// Note special sections as we encounter them.
if ((name == ".rel.dyn" || name == ".rela.dyn") &&
section_header->sh_size > 0) {
found_relocations_section = section;
// Note if relocation section is already packed
has_android_relocations =
section_header->sh_type == SHT_ANDROID_REL ||
section_header->sh_type == SHT_ANDROID_RELA;
}
if (section_header->sh_offset == dynamic_program_header->p_offset) {
found_dynamic_section = section;
}
// Ensure we preserve alignment, repeated later for the data block(s).
CHECK(section_header->sh_addralign <= kPreserveAlignment);
Elf_Data* data = NULL;
while ((data = elf_getdata(section, data)) != NULL) {
CHECK(data->d_align <= kPreserveAlignment);
VerboseLogSectionData(data);
}
}
// Loading failed if we did not find the required special sections.
if (!found_relocations_section) {
LOG(ERROR) << "Missing or empty .rel.dyn or .rela.dyn section";
return false;
}
if (!found_dynamic_section) {
LOG(ERROR) << "Missing .dynamic section";
return false;
}
// Loading failed if we could not identify the relocations type.
if (!has_rel_relocations && !has_rela_relocations) {
LOG(ERROR) << "No relocations sections found";
return false;
}
if (has_rel_relocations && has_rela_relocations) {
LOG(ERROR) << "Multiple relocations sections with different types found, "
<< "not currently supported";
return false;
}
elf_ = elf;
relocations_section_ = found_relocations_section;
dynamic_section_ = found_dynamic_section;
relocations_type_ = has_rel_relocations ? REL : RELA;
has_android_relocations_ = has_android_relocations;
return true;
}
// Helper for ResizeSection(). Adjust the main ELF header for the hole.
template <typename ELF>
static void AdjustElfHeaderForHole(typename ELF::Ehdr* elf_header,
typename ELF::Off hole_start,
ssize_t hole_size) {
if (elf_header->e_phoff > hole_start) {
elf_header->e_phoff += hole_size;
VLOG(1) << "e_phoff adjusted to " << elf_header->e_phoff;
}
if (elf_header->e_shoff > hole_start) {
elf_header->e_shoff += hole_size;
VLOG(1) << "e_shoff adjusted to " << elf_header->e_shoff;
}
}
// Helper for ResizeSection(). Adjust all section headers for the hole.
template <typename ELF>
static void AdjustSectionHeadersForHole(Elf* elf,
typename ELF::Off hole_start,
ssize_t hole_size) {
size_t string_index;
elf_getshdrstrndx(elf, &string_index);
Elf_Scn* section = NULL;
while ((section = elf_nextscn(elf, section)) != NULL) {
auto section_header = ELF::getshdr(section);
std::string name = elf_strptr(elf, string_index, section_header->sh_name);
if (section_header->sh_offset > hole_start) {
section_header->sh_offset += hole_size;
VLOG(1) << "section " << name
<< " sh_offset adjusted to " << section_header->sh_offset;
} else {
section_header->sh_addr -= hole_size;
VLOG(1) << "section " << name
<< " sh_addr adjusted to " << section_header->sh_addr;
}
}
}
// Helpers for ResizeSection(). On packing, reduce p_align for LOAD segments
// to 4kb if larger. On unpacking, restore p_align for LOAD segments if
// packing reduced it to 4kb. Return true if p_align was changed.
template <typename ELF>
static bool ClampLoadSegmentAlignment(typename ELF::Phdr* program_header) {
CHECK(program_header->p_type == PT_LOAD);
// If large, reduce p_align for a LOAD segment to page size on packing.
if (program_header->p_align > kPageSize) {
program_header->p_align = kPageSize;
return true;
}
return false;
}
template <typename ELF>
static bool RestoreLoadSegmentAlignment(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Phdr* program_header) {
CHECK(program_header->p_type == PT_LOAD);
// If p_align was reduced on packing, restore it to its previous value
// on unpacking. We do this by searching for a different LOAD segment
// and setting p_align to that of the other LOAD segment found.
//
// Relies on the following observations:
// - a packable ELF executable has more than one LOAD segment;
// - before packing all LOAD segments have the same p_align;
// - on packing we reduce only one LOAD segment's p_align.
if (program_header->p_align == kPageSize) {
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* other_header = &program_headers[i];
if (other_header->p_type == PT_LOAD && other_header != program_header) {
program_header->p_align = other_header->p_align;
return true;
}
}
LOG(WARNING) << "Cannot find a LOAD segment from which to restore p_align";
}
return false;
}
template <typename ELF>
static bool AdjustLoadSegmentAlignment(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Phdr* program_header,
ssize_t hole_size) {
CHECK(program_header->p_type == PT_LOAD);
bool status = false;
if (hole_size < 0) {
status = ClampLoadSegmentAlignment<ELF>(program_header);
} else if (hole_size > 0) {
status = RestoreLoadSegmentAlignment<ELF>(program_headers,
count,
program_header);
}
return status;
}
// Helper for ResizeSection(). Adjust the offsets of any program headers
// that have offsets currently beyond the hole start, and adjust the
// virtual and physical addrs (and perhaps alignment) of the others.
template <typename ELF>
static void AdjustProgramHeaderFields(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Off hole_start,
ssize_t hole_size) {
int alignment_changes = 0;
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* program_header = &program_headers[i];
// Do not adjust PT_GNU_STACK - it confuses gdb and results
// in incorrect unwinding if the executable is stripped after
// packing.
if (program_header->p_type == PT_GNU_STACK) {
continue;
}
if (program_header->p_offset > hole_start) {
// The hole start is past this segment, so adjust offset.
program_header->p_offset += hole_size;
VLOG(1) << "phdr[" << i
<< "] p_offset adjusted to "<< program_header->p_offset;
} else {
program_header->p_vaddr -= hole_size;
program_header->p_paddr -= hole_size;
// If packing, clamp LOAD segment alignment to 4kb to prevent strip
// from adjusting it unnecessarily if run on a packed file. If
// unpacking, attempt to restore a reduced alignment to its previous
// value. Ensure that we do this on at most one LOAD segment.
if (program_header->p_type == PT_LOAD) {
alignment_changes += AdjustLoadSegmentAlignment<ELF>(program_headers,
count,
program_header,
hole_size);
LOG_IF(FATAL, alignment_changes > 1)
<< "Changed p_align on more than one LOAD segment";
}
VLOG(1) << "phdr[" << i
<< "] p_vaddr adjusted to "<< program_header->p_vaddr
<< "; p_paddr adjusted to "<< program_header->p_paddr
<< "; p_align adjusted to "<< program_header->p_align;
}
}
}
// Helper for ResizeSection(). Find the first loadable segment in the
// file. We expect it to map from file offset zero.
template <typename ELF>
static typename ELF::Phdr* FindLoadSegmentForHole(typename ELF::Phdr* program_headers,
size_t count,
typename ELF::Off hole_start) {
for (size_t i = 0; i < count; ++i) {
typename ELF::Phdr* program_header = &program_headers[i];
if (program_header->p_type == PT_LOAD &&
program_header->p_offset <= hole_start &&
(program_header->p_offset + program_header->p_filesz) >= hole_start ) {
return program_header;
}
}
LOG(FATAL) << "Cannot locate a LOAD segment with hole_start=0x" << std::hex << hole_start;
NOTREACHED();
return nullptr;
}
// Helper for ResizeSection(). Rewrite program headers.
template <typename ELF>
static void RewriteProgramHeadersForHole(Elf* elf,
typename ELF::Off hole_start,
ssize_t hole_size) {
const typename ELF::Ehdr* elf_header = ELF::getehdr(elf);
CHECK(elf_header);
typename ELF::Phdr* elf_program_header = ELF::getphdr(elf);
CHECK(elf_program_header);
const size_t program_header_count = elf_header->e_phnum;
// Locate the segment that we can overwrite to form the new LOAD entry,
// and the segment that we are going to split into two parts.
typename ELF::Phdr* target_load_header =
FindLoadSegmentForHole<ELF>(elf_program_header, program_header_count, hole_start);
VLOG(1) << "phdr[" << target_load_header - elf_program_header << "] adjust";
// Adjust PT_LOAD program header memsz and filesz
target_load_header->p_filesz += hole_size;
target_load_header->p_memsz += hole_size;
// Adjust the offsets and p_vaddrs
AdjustProgramHeaderFields<ELF>(elf_program_header,
program_header_count,
hole_start,
hole_size);
}
// Helper for ResizeSection(). Locate and return the dynamic section.
template <typename ELF>
static Elf_Scn* GetDynamicSection(Elf* elf) {
const typename ELF::Ehdr* elf_header = ELF::getehdr(elf);
CHECK(elf_header);
const typename ELF::Phdr* elf_program_header = ELF::getphdr(elf);
CHECK(elf_program_header);
// Find the program header that describes the dynamic section.
const typename ELF::Phdr* dynamic_program_header = NULL;
for (size_t i = 0; i < elf_header->e_phnum; ++i) {
const typename ELF::Phdr* program_header = &elf_program_header[i];
if (program_header->p_type == PT_DYNAMIC) {
dynamic_program_header = program_header;
}
}
CHECK(dynamic_program_header);
// Now find the section with the same offset as this program header.
Elf_Scn* dynamic_section = NULL;
Elf_Scn* section = NULL;
while ((section = elf_nextscn(elf, section)) != NULL) {
typename ELF::Shdr* section_header = ELF::getshdr(section);
if (section_header->sh_offset == dynamic_program_header->p_offset) {
dynamic_section = section;
}
}
CHECK(dynamic_section != NULL);
return dynamic_section;
}
// Helper for ResizeSection(). Adjust the .dynamic section for the hole.
template <typename ELF>
void ElfFile<ELF>::AdjustDynamicSectionForHole(Elf_Scn* dynamic_section,
typename ELF::Off hole_start,
ssize_t hole_size,
relocations_type_t relocations_type) {
CHECK(relocations_type != NONE);
Elf_Data* data = GetSectionData(dynamic_section);
auto dynamic_base = reinterpret_cast<typename ELF::Dyn*>(data->d_buf);
std::vector<typename ELF::Dyn> dynamics(
dynamic_base,
dynamic_base + data->d_size / sizeof(dynamics[0]));
if (hole_size > 0) { // expanding
hole_start += hole_size;
}
for (size_t i = 0; i < dynamics.size(); ++i) {
typename ELF::Dyn* dynamic = &dynamics[i];
const typename ELF::Sword tag = dynamic->d_tag;
// Any tags that hold offsets are adjustment candidates.
const bool is_adjustable = (tag == DT_PLTGOT ||
tag == DT_HASH ||
tag == DT_GNU_HASH ||
tag == DT_STRTAB ||
tag == DT_SYMTAB ||
tag == DT_RELA ||
tag == DT_INIT ||
tag == DT_FINI ||
tag == DT_REL ||
tag == DT_JMPREL ||
tag == DT_INIT_ARRAY ||
tag == DT_FINI_ARRAY ||
tag == DT_VERSYM ||
tag == DT_VERNEED ||
tag == DT_VERDEF ||
tag == DT_ANDROID_REL||
tag == DT_ANDROID_RELA);
if (is_adjustable && dynamic->d_un.d_ptr <= hole_start) {
dynamic->d_un.d_ptr -= hole_size;
VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag
<< " d_ptr adjusted to " << dynamic->d_un.d_ptr;
}
// DT_RELSZ or DT_RELASZ indicate the overall size of relocations.
// Only one will be present. Adjust by hole size.
if (tag == DT_RELSZ || tag == DT_RELASZ || tag == DT_ANDROID_RELSZ || tag == DT_ANDROID_RELASZ) {
dynamic->d_un.d_val += hole_size;
VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag
<< " d_val adjusted to " << dynamic->d_un.d_val;
}
// Special case: DT_MIPS_RLD_MAP2 stores the difference between dynamic
// entry address and the address of the _r_debug (used by GDB)
// since the dynamic section and target address are on the
// different sides of the hole it needs to be adjusted accordingly
if (tag == DT_MIPS_RLD_MAP2) {
dynamic->d_un.d_val += hole_size;
VLOG(1) << "dynamic[" << i << "] " << dynamic->d_tag
<< " d_val adjusted to " << dynamic->d_un.d_val;
}
// Ignore DT_RELCOUNT and DT_RELACOUNT: (1) nobody uses them and
// technically (2) the relative relocation count is not changed.
// DT_RELENT and DT_RELAENT don't change, ignore them as well.
}
void* section_data = &dynamics[0];
size_t bytes = dynamics.size() * sizeof(dynamics[0]);
RewriteSectionData(dynamic_section, section_data, bytes);
}
// Resize a section. If the new size is larger than the current size, open
// up a hole by increasing file offsets that come after the hole. If smaller
// than the current size, remove the hole by decreasing those offsets.
template <typename ELF>
void ElfFile<ELF>::ResizeSection(Elf* elf, Elf_Scn* section, size_t new_size,
typename ELF::Word new_sh_type,
relocations_type_t relocations_type) {
size_t string_index;
elf_getshdrstrndx(elf, &string_index);
auto section_header = ELF::getshdr(section);
std::string name = elf_strptr(elf, string_index, section_header->sh_name);
if (section_header->sh_size == new_size) {
return;
}
// Require that the section size and the data size are the same. True
// in practice for all sections we resize when packing or unpacking.
Elf_Data* data = GetSectionData(section);
CHECK(data->d_off == 0 && data->d_size == section_header->sh_size);
// Require that the section is not zero-length (that is, has allocated
// data that we can validly expand).
CHECK(data->d_size && data->d_buf);
const auto hole_start = section_header->sh_offset;
const ssize_t hole_size = new_size - data->d_size;
VLOG_IF(1, (hole_size > 0)) << "expand section (" << name << ") size: " <<
data->d_size << " -> " << (data->d_size + hole_size);
VLOG_IF(1, (hole_size < 0)) << "shrink section (" << name << ") size: " <<
data->d_size << " -> " << (data->d_size + hole_size);
// libelf overrides sh_entsize for known sh_types, so it does not matter what we set
// for SHT_REL/SHT_RELA.
typename ELF::Xword new_entsize =
(new_sh_type == SHT_ANDROID_REL || new_sh_type == SHT_ANDROID_RELA) ? 1 : 0;
VLOG(1) << "Update section (" << name << ") entry size: " <<
section_header->sh_entsize << " -> " << new_entsize;
// Resize the data and the section header.
data->d_size += hole_size;
section_header->sh_size += hole_size;
section_header->sh_entsize = new_entsize;
section_header->sh_type = new_sh_type;
// Add the hole size to all offsets in the ELF file that are after the
// start of the hole. If the hole size is positive we are expanding the
// section to create a new hole; if negative, we are closing up a hole.
// Start with the main ELF header.
typename ELF::Ehdr* elf_header = ELF::getehdr(elf);
AdjustElfHeaderForHole<ELF>(elf_header, hole_start, hole_size);
// Adjust all section headers.
AdjustSectionHeadersForHole<ELF>(elf, hole_start, hole_size);
// Rewrite the program headers to either split or coalesce segments,
// and adjust dynamic entries to match.
RewriteProgramHeadersForHole<ELF>(elf, hole_start, hole_size);
Elf_Scn* dynamic_section = GetDynamicSection<ELF>(elf);
AdjustDynamicSectionForHole(dynamic_section, hole_start, hole_size, relocations_type);
}
// Find the first slot in a dynamics array with the given tag. The array
// always ends with a free (unused) element, and which we exclude from the
// search. Returns dynamics->size() if not found.
template <typename ELF>
static size_t FindDynamicEntry(typename ELF::Sword tag,
std::vector<typename ELF::Dyn>* dynamics) {
// Loop until the penultimate entry. We exclude the end sentinel.
for (size_t i = 0; i < dynamics->size() - 1; ++i) {
if (dynamics->at(i).d_tag == tag) {
return i;
}
}
// The tag was not found.
return dynamics->size();
}
// Replace dynamic entry.
template <typename ELF>
static void ReplaceDynamicEntry(typename ELF::Sword tag,
const typename ELF::Dyn& dyn,
std::vector<typename ELF::Dyn>* dynamics) {
const size_t slot = FindDynamicEntry<ELF>(tag, dynamics);
if (slot == dynamics->size()) {
LOG(FATAL) << "Dynamic slot is not found for tag=" << tag;
}
// Replace this entry with the one supplied.
dynamics->at(slot) = dyn;
VLOG(1) << "dynamic[" << slot << "] overwritten with " << dyn.d_tag;
}
// Remove relative entries from dynamic relocations and write as packed
// data into android packed relocations.
template <typename ELF>
bool ElfFile<ELF>::PackRelocations() {
// Load the ELF file into libelf.
if (!Load()) {
LOG(ERROR) << "Failed to load as ELF";
return false;
}
// Retrieve the current dynamic relocations section data.
Elf_Data* data = GetSectionData(relocations_section_);
// we always pack rela, because packed format is pretty much the same
std::vector<typename ELF::Rela> relocations;
if (relocations_type_ == REL) {
// Convert data to a vector of relocations.
const typename ELF::Rel* relocations_base = reinterpret_cast<typename ELF::Rel*>(data->d_buf);
ConvertRelArrayToRelaVector(relocations_base,
data->d_size / sizeof(typename ELF::Rel), &relocations);
VLOG(1) << "Relocations : REL";
} else if (relocations_type_ == RELA) {
// Convert data to a vector of relocations with addends.
const typename ELF::Rela* relocations_base = reinterpret_cast<typename ELF::Rela*>(data->d_buf);
relocations = std::vector<typename ELF::Rela>(
relocations_base,
relocations_base + data->d_size / sizeof(relocations[0]));
VLOG(1) << "Relocations : RELA";
} else {
NOTREACHED();
}
return PackTypedRelocations(&relocations);
}
// Helper for PackRelocations(). Rel type is one of ELF::Rel or ELF::Rela.
template <typename ELF>
bool ElfFile<ELF>::PackTypedRelocations(std::vector<typename ELF::Rela>* relocations) {
typedef typename ELF::Rela Rela;
if (has_android_relocations_) {
LOG(INFO) << "Relocation table is already packed";
return true;
}
// If no relocations then we have nothing packable. Perhaps
// the shared object has already been packed?
if (relocations->empty()) {
LOG(ERROR) << "No relocations found";
return false;
}
const size_t rel_size =
relocations_type_ == RELA ? sizeof(typename ELF::Rela) : sizeof(typename ELF::Rel);
const size_t initial_bytes = relocations->size() * rel_size;
VLOG(1) << "Unpacked : " << initial_bytes << " bytes";
std::vector<uint8_t> packed;
RelocationPacker<ELF> packer;
// Pack relocations: dry run to estimate memory savings.
packer.PackRelocations(*relocations, &packed);
const size_t packed_bytes_estimate = packed.size() * sizeof(packed[0]);
VLOG(1) << "Packed (no padding): " << packed_bytes_estimate << " bytes";
if (packed.empty()) {
LOG(INFO) << "Too few relocations to pack";
return true;
}
// Pre-calculate the size of the hole we will close up when we rewrite
// dynamic relocations. We have to adjust relocation addresses to
// account for this.
typename ELF::Shdr* section_header = ELF::getshdr(relocations_section_);
ssize_t hole_size = initial_bytes - packed_bytes_estimate;
// hole_size needs to be page_aligned.
hole_size -= hole_size % kPreserveAlignment;
LOG(INFO) << "Compaction : " << hole_size << " bytes";
// Adjusting for alignment may have removed any packing benefit.
if (hole_size == 0) {
LOG(INFO) << "Too few relocations to pack after alignment";
return true;
}
if (hole_size <= 0) {
LOG(INFO) << "Packing relocations saves no space";
return true;
}
size_t data_padding_bytes = is_padding_relocations_ ?
initial_bytes - packed_bytes_estimate :
initial_bytes - hole_size - packed_bytes_estimate;
// pad data
std::vector<uint8_t> padding(data_padding_bytes, 0);
packed.insert(packed.end(), padding.begin(), padding.end());
const void* packed_data = &packed[0];
// Run a loopback self-test as a check that packing is lossless.
std::vector<Rela> unpacked;
packer.UnpackRelocations(packed, &unpacked);
CHECK(unpacked.size() == relocations->size());
CHECK(!memcmp(&unpacked[0],
&relocations->at(0),
unpacked.size() * sizeof(unpacked[0])));
// Rewrite the current dynamic relocations section with packed one then shrink it to size.
const size_t bytes = packed.size() * sizeof(packed[0]);
ResizeSection(elf_, relocations_section_, bytes,
relocations_type_ == REL ? SHT_ANDROID_REL : SHT_ANDROID_RELA, relocations_type_);
RewriteSectionData(relocations_section_, packed_data, bytes);
// TODO (dimitry): fix string table and replace .rel.dyn/plt with .android.rel.dyn/plt
// Rewrite .dynamic and rename relocation tags describing the packed android
// relocations.
Elf_Data* data = GetSectionData(dynamic_section_);
const typename ELF::Dyn* dynamic_base = reinterpret_cast<typename ELF::Dyn*>(data->d_buf);
std::vector<typename ELF::Dyn> dynamics(
dynamic_base,
dynamic_base + data->d_size / sizeof(dynamics[0]));
section_header = ELF::getshdr(relocations_section_);
{
typename ELF::Dyn dyn;
dyn.d_tag = relocations_type_ == REL ? DT_ANDROID_REL : DT_ANDROID_RELA;
dyn.d_un.d_ptr = section_header->sh_addr;
ReplaceDynamicEntry<ELF>(relocations_type_ == REL ? DT_REL : DT_RELA, dyn, &dynamics);
}
{
typename ELF::Dyn dyn;
dyn.d_tag = relocations_type_ == REL ? DT_ANDROID_RELSZ : DT_ANDROID_RELASZ;
dyn.d_un.d_val = section_header->sh_size;
ReplaceDynamicEntry<ELF>(relocations_type_ == REL ? DT_RELSZ : DT_RELASZ, dyn, &dynamics);
}
const void* dynamics_data = &dynamics[0];
const size_t dynamics_bytes = dynamics.size() * sizeof(dynamics[0]);
RewriteSectionData(dynamic_section_, dynamics_data, dynamics_bytes);
Flush();
return true;
}
// Find packed relative relocations in the packed android relocations
// section, unpack them, and rewrite the dynamic relocations section to
// contain unpacked data.
template <typename ELF>
bool ElfFile<ELF>::UnpackRelocations() {
// Load the ELF file into libelf.
if (!Load()) {
LOG(ERROR) << "Failed to load as ELF";
return false;
}
typename ELF::Shdr* section_header = ELF::getshdr(relocations_section_);
// Retrieve the current packed android relocations section data.
Elf_Data* data = GetSectionData(relocations_section_);
// Convert data to a vector of bytes.
const uint8_t* packed_base = reinterpret_cast<uint8_t*>(data->d_buf);
std::vector<uint8_t> packed(
packed_base,
packed_base + data->d_size / sizeof(packed[0]));
if ((section_header->sh_type == SHT_ANDROID_RELA || section_header->sh_type == SHT_ANDROID_REL) &&
packed.size() > 3 &&
packed[0] == 'A' &&
packed[1] == 'P' &&
packed[2] == 'S' &&
packed[3] == '2') {
LOG(INFO) << "Relocations : " << (relocations_type_ == REL ? "REL" : "RELA");
} else {
LOG(ERROR) << "Packed relocations not found (not packed?)";
return false;
}
return UnpackTypedRelocations(packed);
}
// Helper for UnpackRelocations(). Rel type is one of ELF::Rel or ELF::Rela.
template <typename ELF>
bool ElfFile<ELF>::UnpackTypedRelocations(const std::vector<uint8_t>& packed) {
// Unpack the data to re-materialize the relative relocations.
const size_t packed_bytes = packed.size() * sizeof(packed[0]);
LOG(INFO) << "Packed : " << packed_bytes << " bytes";
std::vector<typename ELF::Rela> unpacked_relocations;
RelocationPacker<ELF> packer;
packer.UnpackRelocations(packed, &unpacked_relocations);
const size_t relocation_entry_size =
relocations_type_ == REL ? sizeof(typename ELF::Rel) : sizeof(typename ELF::Rela);
const size_t unpacked_bytes = unpacked_relocations.size() * relocation_entry_size;
LOG(INFO) << "Unpacked : " << unpacked_bytes << " bytes";
// Retrieve the current dynamic relocations section data.
Elf_Data* data = GetSectionData(relocations_section_);
LOG(INFO) << "Relocations : " << unpacked_relocations.size() << " entries";
// If we found the same number of null relocation entries in the dynamic
// relocations section as we hold as unpacked relative relocations, then
// this is a padded file.
const bool is_padded = packed_bytes == unpacked_bytes;
// Unless padded, pre-apply relative relocations to account for the
// hole, and pre-adjust all relocation offsets accordingly.
typename ELF::Shdr* section_header = ELF::getshdr(relocations_section_);
if (!is_padded) {
LOG(INFO) << "Expansion : " << unpacked_bytes - packed_bytes << " bytes";
}
// Rewrite the current dynamic relocations section with unpacked version of
// relocations.
const void* section_data = nullptr;
std::vector<typename ELF::Rel> unpacked_rel_relocations;
if (relocations_type_ == RELA) {
section_data = &unpacked_relocations[0];
} else if (relocations_type_ == REL) {
ConvertRelaVectorToRelVector(unpacked_relocations, &unpacked_rel_relocations);
section_data = &unpacked_rel_relocations[0];
} else {
NOTREACHED();
}
ResizeSection(elf_, relocations_section_, unpacked_bytes,
relocations_type_ == REL ? SHT_REL : SHT_RELA, relocations_type_);
RewriteSectionData(relocations_section_, section_data, unpacked_bytes);
// Rewrite .dynamic to remove two tags describing packed android relocations.
data = GetSectionData(dynamic_section_);
const typename ELF::Dyn* dynamic_base = reinterpret_cast<typename ELF::Dyn*>(data->d_buf);
std::vector<typename ELF::Dyn> dynamics(
dynamic_base,
dynamic_base + data->d_size / sizeof(dynamics[0]));
{
typename ELF::Dyn dyn;
dyn.d_tag = relocations_type_ == REL ? DT_REL : DT_RELA;
dyn.d_un.d_ptr = section_header->sh_addr;
ReplaceDynamicEntry<ELF>(relocations_type_ == REL ? DT_ANDROID_REL : DT_ANDROID_RELA,
dyn, &dynamics);
}
{
typename ELF::Dyn dyn;
dyn.d_tag = relocations_type_ == REL ? DT_RELSZ : DT_RELASZ;
dyn.d_un.d_val = section_header->sh_size;
ReplaceDynamicEntry<ELF>(relocations_type_ == REL ? DT_ANDROID_RELSZ : DT_ANDROID_RELASZ,
dyn, &dynamics);
}
const void* dynamics_data = &dynamics[0];
const size_t dynamics_bytes = dynamics.size() * sizeof(dynamics[0]);
RewriteSectionData(dynamic_section_, dynamics_data, dynamics_bytes);
Flush();
return true;
}
// Flush rewritten shared object file data.
template <typename ELF>
void ElfFile<ELF>::Flush() {
// Flag all ELF data held in memory as needing to be written back to the
// file, and tell libelf that we have controlled the file layout.
elf_flagelf(elf_, ELF_C_SET, ELF_F_DIRTY);
elf_flagelf(elf_, ELF_C_SET, ELF_F_LAYOUT);
// Write ELF data back to disk.
const off_t file_bytes = elf_update(elf_, ELF_C_WRITE);
if (file_bytes == -1) {
LOG(ERROR) << "elf_update failed: " << elf_errmsg(elf_errno());
}
CHECK(file_bytes > 0);
VLOG(1) << "elf_update returned: " << file_bytes;
// Clean up libelf, and truncate the output file to the number of bytes
// written by elf_update().
elf_end(elf_);
elf_ = NULL;
const int truncate = ftruncate(fd_, file_bytes);
CHECK(truncate == 0);
}
template <typename ELF>
void ElfFile<ELF>::ConvertRelArrayToRelaVector(const typename ELF::Rel* rel_array,
size_t rel_array_size,
std::vector<typename ELF::Rela>* rela_vector) {
for (size_t i = 0; i<rel_array_size; ++i) {
typename ELF::Rela rela;
rela.r_offset = rel_array[i].r_offset;
rela.r_info = rel_array[i].r_info;
rela.r_addend = 0;
rela_vector->push_back(rela);
}
}
template <typename ELF>
void ElfFile<ELF>::ConvertRelaVectorToRelVector(const std::vector<typename ELF::Rela>& rela_vector,
std::vector<typename ELF::Rel>* rel_vector) {
for (auto rela : rela_vector) {
typename ELF::Rel rel;
rel.r_offset = rela.r_offset;
rel.r_info = rela.r_info;
CHECK(rela.r_addend == 0);
rel_vector->push_back(rel);
}
}
template class ElfFile<ELF32_traits>;
template class ElfFile<ELF64_traits>;
} // namespace relocation_packer

View File

@ -0,0 +1,121 @@
// Copyright 2014 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.
// ELF shared object file updates handler.
//
// Provides functions to pack relocations in the .rel.dyn or .rela.dyn
// sections, and unpack to return the file to its pre-packed state.
//
// SetPadding() causes PackRelocations() to pad .rel.dyn or .rela.dyn with
// NONE-type entries rather than cutting a hole out of the shared object
// file. This keeps all load addresses and offsets constant, and enables
// easier debugging and testing.
//
// A packed shared object file is shorter than its non-packed original.
// Unpacking a packed file restores the file to its non-packed state.
#ifndef TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
#define TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
#include <string.h>
#include <vector>
#include "elf.h"
#include "libelf.h"
#include "packer.h"
namespace relocation_packer {
// An ElfFile reads shared objects, and shuttles relative relocations
// between .rel.dyn or .rela.dyn and .android.rel.dyn or .android.rela.dyn
// sections.
template <typename ELF>
class ElfFile {
public:
explicit ElfFile(int fd)
: fd_(fd), is_padding_relocations_(false), elf_(NULL),
relocations_section_(NULL), dynamic_section_(NULL),
relocations_type_(NONE), has_android_relocations_(false) {}
~ElfFile() {}
// Set padding mode. When padding, PackRelocations() will not shrink
// the .rel.dyn or .rela.dyn section, but instead replace relative with
// NONE-type entries.
// |flag| is true to pad .rel.dyn or .rela.dyn, false to shrink it.
inline void SetPadding(bool flag) { is_padding_relocations_ = flag; }
// Transfer relative relocations from .rel.dyn or .rela.dyn to a packed
// representation in .android.rel.dyn or .android.rela.dyn. Returns true
// on success.
bool PackRelocations();
// Transfer relative relocations from a packed representation in
// .android.rel.dyn or .android.rela.dyn to .rel.dyn or .rela.dyn. Returns
// true on success.
bool UnpackRelocations();
private:
enum relocations_type_t {
NONE = 0, REL, RELA
};
// Load a new ElfFile from a filedescriptor. If flushing, the file must
// be open for read/write. Returns true on successful ELF file load.
// |fd| is an open file descriptor for the shared object.
bool Load();
// Templated packer, helper for PackRelocations(). Rel type is one of
// ELF::Rel or ELF::Rela.
bool PackTypedRelocations(std::vector<typename ELF::Rela>* relocations);
// Templated unpacker, helper for UnpackRelocations(). Rel type is one of
// ELF::Rel or ELF::Rela.
bool UnpackTypedRelocations(const std::vector<uint8_t>& packed);
// Write ELF file changes.
void Flush();
void AdjustRelativeRelocationTargets(typename ELF::Off hole_start,
ssize_t hole_size,
std::vector<typename ELF::Rela>* relocations);
static void ResizeSection(Elf* elf, Elf_Scn* section, size_t new_size,
typename ELF::Word new_sh_type, relocations_type_t relocations_type);
static void AdjustDynamicSectionForHole(Elf_Scn* dynamic_section,
typename ELF::Off hole_start,
ssize_t hole_size,
relocations_type_t relocations_type);
static void ConvertRelArrayToRelaVector(const typename ELF::Rel* rel_array, size_t rel_array_size,
std::vector<typename ELF::Rela>* rela_vector);
static void ConvertRelaVectorToRelVector(const std::vector<typename ELF::Rela>& rela_vector,
std::vector<typename ELF::Rel>* rel_vector);
// File descriptor opened on the shared object.
int fd_;
// If set, pad rather than shrink .rel.dyn or .rela.dyn. Primarily for
// debugging, allows packing to be checked without affecting load addresses.
bool is_padding_relocations_;
// Libelf handle, assigned by Load().
Elf* elf_;
// Sections that we manipulate, assigned by Load().
Elf_Scn* relocations_section_;
Elf_Scn* dynamic_section_;
// Relocation type found, assigned by Load().
relocations_type_t relocations_type_;
// Elf-file has android relocations section
bool has_android_relocations_;
};
} // namespace relocation_packer
#endif // TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_

View File

@ -0,0 +1,218 @@
// Copyright 2014 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.
#include "elf_file.h"
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include <vector>
#include "debug.h"
#include "elf_traits.h"
#include "gtest/gtest.h"
namespace {
void GetDataFilePath(const char* name, std::string* path) {
std::string data_dir;
const char* bindir = getenv("bindir");
if (bindir) {
data_dir = std::string(bindir);
} else {
char path[PATH_MAX];
memset(path, 0, sizeof(path));
ASSERT_NE(-1, readlink("/proc/self/exe", path, sizeof(path) - 1));
data_dir = std::string(path);
size_t pos = data_dir.rfind('/');
ASSERT_NE(std::string::npos, pos);
data_dir.erase(pos);
}
*path = data_dir + "/" + name;
}
void OpenRelocsTestFile(const char* name, FILE** stream) {
std::string path;
GetDataFilePath(name, &path);
FILE* testfile = fopen(path.c_str(), "rb");
ASSERT_FALSE(testfile == NULL) << "Error opening '" << path << "'";
FILE* temporary = tmpfile();
ASSERT_FALSE(temporary == NULL);
static const size_t buffer_size = 4096;
unsigned char buffer[buffer_size];
size_t bytes;
do {
bytes = fread(buffer, 1, sizeof(buffer), testfile);
ASSERT_EQ(bytes, fwrite(buffer, 1, bytes, temporary));
} while (bytes > 0);
ASSERT_EQ(0, fclose(testfile));
ASSERT_EQ(0, fseek(temporary, 0, SEEK_SET));
ASSERT_EQ(0, lseek(fileno(temporary), 0, SEEK_SET));
*stream = temporary;
}
void OpenRelocsTestFiles(const std::string& arch, FILE** relocs_so, FILE** packed_relocs_so) {
const std::string base = std::string("elf_file_unittest_relocs_") + arch;
const std::string relocs = base + ".so";
const std::string packed_relocs = base + "_packed.so";
OpenRelocsTestFile(relocs.c_str(), relocs_so);
OpenRelocsTestFile(packed_relocs.c_str(), packed_relocs_so);
}
void CloseRelocsTestFile(FILE* temporary) {
fclose(temporary);
}
void CloseRelocsTestFiles(FILE* relocs_so, FILE* packed_relocs_so) {
CloseRelocsTestFile(relocs_so);
CloseRelocsTestFile(packed_relocs_so);
}
void CheckFileContentsEqual(FILE* first, FILE* second) {
ASSERT_EQ(0, fseek(first, 0, SEEK_SET));
ASSERT_EQ(0, fseek(second, 0, SEEK_SET));
static const size_t buffer_size = 4096;
unsigned char first_buffer[buffer_size];
unsigned char second_buffer[buffer_size];
do {
size_t first_read = fread(first_buffer, 1, sizeof(first_buffer), first);
size_t second_read = fread(second_buffer, 1, sizeof(second_buffer), second);
EXPECT_EQ(first_read, second_read);
EXPECT_EQ(0, memcmp(first_buffer, second_buffer, first_read));
} while (!feof(first) && !feof(second));
EXPECT_TRUE(feof(first) && feof(second));
}
template <typename ELF>
static void ProcessUnpack(FILE* relocs_so, FILE* packed_relocs_so) {
relocation_packer::ElfFile<ELF> elf_file(fileno(packed_relocs_so));
// Ensure packing already packed elf-file does not fail the build.
EXPECT_TRUE(elf_file.PackRelocations());
// Unpack golden relocations, and check files are now identical.
EXPECT_TRUE(elf_file.UnpackRelocations());
CheckFileContentsEqual(packed_relocs_so, relocs_so);
CloseRelocsTestFiles(relocs_so, packed_relocs_so);
}
static void RunUnpackRelocationsTestFor(const std::string& arch) {
ASSERT_NE(static_cast<uint32_t>(EV_NONE), elf_version(EV_CURRENT));
FILE* relocs_so = NULL;
FILE* packed_relocs_so = NULL;
OpenRelocsTestFiles(arch, &relocs_so, &packed_relocs_so);
if (relocs_so != NULL && packed_relocs_so != NULL) {
// lets detect elf class
ASSERT_EQ(0, fseek(relocs_so, EI_CLASS, SEEK_SET))
<< "Invalid file length: " << strerror(errno);
uint8_t elf_class = 0;
ASSERT_EQ(1U, fread(&elf_class, 1, 1, relocs_so));
ASSERT_EQ(0, fseek(relocs_so, 0, SEEK_SET));
if (elf_class == ELFCLASS32) {
ProcessUnpack<ELF32_traits>(relocs_so, packed_relocs_so);
} else {
ProcessUnpack<ELF64_traits>(relocs_so, packed_relocs_so);
}
}
}
template <typename ELF>
static void ProcessPack(FILE* relocs_so, FILE* packed_relocs_so) {
relocation_packer::ElfFile<ELF> elf_file(fileno(relocs_so));
// Ensure unpacking fails (not packed).
EXPECT_FALSE(elf_file.UnpackRelocations());
// Pack relocations, and check files are now identical.
EXPECT_TRUE(elf_file.PackRelocations());
CheckFileContentsEqual(relocs_so, packed_relocs_so);
CloseRelocsTestFiles(relocs_so, packed_relocs_so);
}
static void RunPackRelocationsTestFor(const std::string& arch) {
ASSERT_NE(static_cast<uint32_t>(EV_NONE), elf_version(EV_CURRENT));
FILE* relocs_so = NULL;
FILE* packed_relocs_so = NULL;
OpenRelocsTestFiles(arch, &relocs_so, &packed_relocs_so);
if (relocs_so != NULL && packed_relocs_so != NULL) {
// lets detect elf class
ASSERT_EQ(0, fseek(packed_relocs_so, EI_CLASS, SEEK_SET))
<< "Invalid file length: " << strerror(errno);
uint8_t elf_class = 0;
ASSERT_EQ(1U, fread(&elf_class, 1, 1, packed_relocs_so));
fseek(packed_relocs_so, 0, SEEK_SET);
if (elf_class == ELFCLASS32) {
ProcessPack<ELF32_traits>(relocs_so, packed_relocs_so);
} else {
ProcessPack<ELF64_traits>(relocs_so, packed_relocs_so);
}
}
}
} // namespace
namespace relocation_packer {
TEST(ElfFile, PackRelocationsArm32) {
RunPackRelocationsTestFor("arm32");
}
TEST(ElfFile, PackRelocationsArm64) {
RunPackRelocationsTestFor("arm64");
}
TEST(ElfFile, PackRelocationsMips32) {
RunPackRelocationsTestFor("mips32");
}
TEST(ElfFile, PackRelocationsIa32) {
RunPackRelocationsTestFor("ia32");
}
TEST(ElfFile, PackRelocationsX64) {
RunPackRelocationsTestFor("x64");
}
TEST(ElfFile, UnpackRelocationsArm32) {
RunUnpackRelocationsTestFor("arm32");
}
TEST(ElfFile, UnpackRelocationsArm64) {
RunUnpackRelocationsTestFor("arm64");
}
TEST(ElfFile, UnpackRelocationsMips32) {
RunUnpackRelocationsTestFor("mips32");
}
TEST(ElfFile, UnpackRelocationsIa32) {
RunUnpackRelocationsTestFor("ia32");
}
TEST(ElfFile, UnpackRelocationsX64) {
RunUnpackRelocationsTestFor("x64");
}
} // namespace relocation_packer

View File

@ -0,0 +1,68 @@
// Copyright 2014 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.
// Target-specific ELF type traits.
#ifndef TOOLS_RELOCATION_PACKER_SRC_ELF_TRAITS_H_
#define TOOLS_RELOCATION_PACKER_SRC_ELF_TRAITS_H_
#include "elf.h"
#include "libelf.h"
#if !defined(DT_MIPS_RLD_MAP2)
#define DT_MIPS_RLD_MAP2 0x70000035
#endif
// ELF is a traits structure used to provide convenient aliases for
// 32/64 bit Elf types and functions, depending on the target file.
struct ELF32_traits {
typedef Elf32_Addr Addr;
typedef Elf32_Dyn Dyn;
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Off Off;
typedef Elf32_Phdr Phdr;
typedef Elf32_Rel Rel;
typedef Elf32_Rela Rela;
typedef Elf32_Shdr Shdr;
typedef Elf32_Sword Sword;
typedef Elf32_Sxword Sxword;
typedef Elf32_Sym Sym;
typedef Elf32_Word Word;
typedef Elf32_Xword Xword;
typedef Elf32_Half Half;
static inline Ehdr* getehdr(Elf* elf) { return elf32_getehdr(elf); }
static inline Phdr* getphdr(Elf* elf) { return elf32_getphdr(elf); }
static inline Shdr* getshdr(Elf_Scn* scn) { return elf32_getshdr(scn); }
static inline Word elf_r_type(Word info) { return ELF32_R_TYPE(info); }
static inline int elf_st_type(uint8_t info) { return ELF32_ST_TYPE(info); }
static inline Word elf_r_sym(Word info) { return ELF32_R_SYM(info); }
};
struct ELF64_traits {
typedef Elf64_Addr Addr;
typedef Elf64_Dyn Dyn;
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Off Off;
typedef Elf64_Phdr Phdr;
typedef Elf64_Rel Rel;
typedef Elf64_Rela Rela;
typedef Elf64_Shdr Shdr;
typedef Elf64_Sword Sword;
typedef Elf64_Sxword Sxword;
typedef Elf64_Sym Sym;
typedef Elf64_Word Word;
typedef Elf64_Xword Xword;
typedef Elf64_Half Half;
static inline Ehdr* getehdr(Elf* elf) { return elf64_getehdr(elf); }
static inline Phdr* getphdr(Elf* elf) { return elf64_getphdr(elf); }
static inline Shdr* getshdr(Elf_Scn* scn) { return elf64_getshdr(scn); }
static inline Xword elf_r_type(Xword info) { return ELF64_R_TYPE(info); }
static inline int elf_st_type(uint8_t info) { return ELF64_ST_TYPE(info); }
static inline Word elf_r_sym(Xword info) { return ELF64_R_SYM(info); }
};
#endif // TOOLS_RELOCATION_PACKER_SRC_ELF_TRAITS_H_

View File

@ -0,0 +1,150 @@
// Copyright 2014 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.
// Tool to pack and unpack relative relocations in a shared library.
//
// Invoke with -v to trace actions taken when packing or unpacking.
// Invoke with -p to pad removed relocations with R_*_NONE. Suppresses
// shrinking of .rel.dyn.
// See PrintUsage() below for full usage details.
//
// NOTE: Breaks with libelf 0.152, which is buggy. libelf 0.158 works.
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string>
#include "debug.h"
#include "elf_file.h"
#include "elf_traits.h"
#include "libelf.h"
#include "nativehelper/ScopedFd.h"
static void PrintUsage(const char* argv0) {
std::string temporary = argv0;
const size_t last_slash = temporary.find_last_of("/");
if (last_slash != temporary.npos) {
temporary.erase(0, last_slash + 1);
}
const char* basename = temporary.c_str();
printf(
"Usage: %s [-u] [-v] [-p] file\n\n"
"Pack or unpack relative relocations in a shared library.\n\n"
" -u, --unpack unpack previously packed relative relocations\n"
" -v, --verbose trace object file modifications (for debugging)\n"
" -p, --pad do not shrink relocations, but pad (for debugging)\n\n",
basename);
printf(
"Debug sections are not handled, so packing should not be used on\n"
"shared libraries compiled for debugging or otherwise unstripped.\n");
}
int main(int argc, char* argv[]) {
bool is_unpacking = false;
bool is_verbose = false;
bool is_padding = false;
static const option options[] = {
{"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'},
{"help", 0, 0, 'h'}, {NULL, 0, 0, 0}
};
bool has_options = true;
while (has_options) {
int c = getopt_long(argc, argv, "uvph", options, NULL);
switch (c) {
case 'u':
is_unpacking = true;
break;
case 'v':
is_verbose = true;
break;
case 'p':
is_padding = true;
break;
case 'h':
PrintUsage(argv[0]);
return 0;
case '?':
LOG(INFO) << "Try '" << argv[0] << " --help' for more information.";
return 1;
case -1:
has_options = false;
break;
default:
NOTREACHED();
return 1;
}
}
if (optind != argc - 1) {
LOG(INFO) << "Try '" << argv[0] << " --help' for more information.";
return 1;
}
if (elf_version(EV_CURRENT) == EV_NONE) {
LOG(WARNING) << "Elf Library is out of date!";
}
const char* file = argv[argc - 1];
ScopedFd fd(open(file, O_RDWR));
if (fd.get() == -1) {
LOG(ERROR) << file << ": " << strerror(errno);
return 1;
}
if (is_verbose)
relocation_packer::Logger::SetVerbose(1);
// We need to detect elf class in order to create
// correct implementation
uint8_t e_ident[EI_NIDENT];
if (TEMP_FAILURE_RETRY(read(fd.get(), e_ident, EI_NIDENT) != EI_NIDENT)) {
LOG(ERROR) << file << ": failed to read elf header:" << strerror(errno);
return 1;
}
if (TEMP_FAILURE_RETRY(lseek(fd.get(), 0, SEEK_SET)) != 0) {
LOG(ERROR) << file << ": lseek to 0 failed:" << strerror(errno);
return 1;
}
bool status = false;
if (e_ident[EI_CLASS] == ELFCLASS32) {
relocation_packer::ElfFile<ELF32_traits> elf_file(fd.get());
elf_file.SetPadding(is_padding);
if (is_unpacking) {
status = elf_file.UnpackRelocations();
} else {
status = elf_file.PackRelocations();
}
} else if (e_ident[EI_CLASS] == ELFCLASS64) {
relocation_packer::ElfFile<ELF64_traits> elf_file(fd.get());
elf_file.SetPadding(is_padding);
if (is_unpacking) {
status = elf_file.UnpackRelocations();
} else {
status = elf_file.PackRelocations();
}
} else {
LOG(ERROR) << file << ": unknown ELFCLASS: " << e_ident[EI_CLASS];
return 1;
}
if (!status) {
LOG(ERROR) << file << ": failed to pack/unpack file";
return 1;
}
return 0;
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (C) 2009 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.
*/
#ifndef SCOPED_FD_H_included
#define SCOPED_FD_H_included
#include <unistd.h>
// Local definition of DISALLOW_COPY_AND_ASSIGN, avoids depending on base.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
// A smart pointer that closes the given fd on going out of scope.
// Use this when the fd is incidental to the purpose of your function,
// but needs to be cleaned up on exit.
class ScopedFd {
public:
explicit ScopedFd(int fd) : fd_(fd) {
}
~ScopedFd() {
reset();
}
int get() const {
return fd_;
}
int release() __attribute__((warn_unused_result)) {
int localFd = fd_;
fd_ = -1;
return localFd;
}
void reset(int new_fd = -1) {
if (fd_ != -1) {
TEMP_FAILURE_RETRY(close(fd_));
}
fd_ = new_fd;
}
private:
int fd_;
DISALLOW_COPY_AND_ASSIGN(ScopedFd);
};
#endif // SCOPED_FD_H_included

View File

@ -0,0 +1,67 @@
// Copyright 2014 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.
#include "packer.h"
#include <vector>
#include "debug.h"
#include "delta_encoder.h"
#include "elf_traits.h"
#include "sleb128.h"
namespace relocation_packer {
// Pack relocations into a group encoded packed representation.
template <typename ELF>
void RelocationPacker<ELF>::PackRelocations(const std::vector<typename ELF::Rela>& relocations,
std::vector<uint8_t>* packed) {
// Run-length encode.
std::vector<typename ELF::Addr> packed_words;
RelocationDeltaCodec<ELF> codec;
codec.Encode(relocations, &packed_words);
// If insufficient data do nothing.
if (packed_words.empty())
return;
Sleb128Encoder<typename ELF::Addr> sleb128_encoder;
std::vector<uint8_t> sleb128_packed;
sleb128_encoder.EnqueueAll(packed_words);
sleb128_encoder.GetEncoding(&sleb128_packed);
packed->push_back('A');
packed->push_back('P');
packed->push_back('S');
packed->push_back('2');
packed->insert(packed->end(), sleb128_packed.begin(), sleb128_packed.end());
}
// Unpack relative relocations from a run-length encoded packed
// representation.
template <typename ELF>
void RelocationPacker<ELF>::UnpackRelocations(
const std::vector<uint8_t>& packed,
std::vector<typename ELF::Rela>* relocations) {
std::vector<typename ELF::Addr> packed_words;
CHECK(packed.size() > 4 &&
packed[0] == 'A' &&
packed[1] == 'P' &&
packed[2] == 'S' &&
packed[3] == '2');
Sleb128Decoder<typename ELF::Addr> decoder(packed, 4);
decoder.DequeueAll(&packed_words);
RelocationDeltaCodec<ELF> codec;
codec.Decode(packed_words, relocations);
}
template class RelocationPacker<ELF32_traits>;
template class RelocationPacker<ELF64_traits>;
} // namespace relocation_packer

View File

@ -0,0 +1,37 @@
// Copyright 2014 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.
// Pack relative relocations into a more compact form.
#ifndef TOOLS_RELOCATION_PACKER_SRC_PACKER_H_
#define TOOLS_RELOCATION_PACKER_SRC_PACKER_H_
#include <stdint.h>
#include <vector>
#include "elf.h"
namespace relocation_packer {
// A RelocationPacker packs vectors of relocations into more
// compact forms, and unpacks them to reproduce the pre-packed data.
template <typename ELF>
class RelocationPacker {
public:
// Pack relocations into a more compact form.
// |relocations| is a vector of relocation structs.
// |packed| is the vector of packed bytes into which relocations are packed.
static void PackRelocations(const std::vector<typename ELF::Rela>& relocations,
std::vector<uint8_t>* packed);
// Unpack relocations from their more compact form.
// |packed| is the vector of packed relocations.
// |relocations| is a vector of unpacked relocation structs.
static void UnpackRelocations(const std::vector<uint8_t>& packed,
std::vector<typename ELF::Rela>* relocations);
};
} // namespace relocation_packer
#endif // TOOLS_RELOCATION_PACKER_SRC_PACKER_H_

View File

@ -0,0 +1,300 @@
// Copyright 2014 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.
#include "packer.h"
#include <vector>
#include "elf.h"
#include "elf_traits.h"
#include "gtest/gtest.h"
template <typename ELF>
static void AddRelocation(typename ELF::Addr addr,
typename ELF::Xword info,
typename ELF::Sxword addend,
std::vector<typename ELF::Rela>* relocations) {
typename ELF::Rela relocation;
relocation.r_offset = addr;
relocation.r_info = info;
relocation.r_addend = addend;
relocations->push_back(relocation);
}
template <typename ELF>
static bool CheckRelocation(typename ELF::Addr addr,
typename ELF::Xword info,
typename ELF::Sxword addend,
const typename ELF::Rela& relocation) {
return relocation.r_offset == addr &&
relocation.r_info == info &&
relocation.r_addend == addend;
}
namespace relocation_packer {
template <typename ELF>
static void DoPackNoAddend() {
std::vector<typename ELF::Rela> relocations;
std::vector<uint8_t> packed;
bool is_32 = sizeof(typename ELF::Addr) == 4;
// Initial relocation.
AddRelocation<ELF>(0xd1ce0000, 0x11, 0, &relocations);
// Two more relocations, 4 byte deltas.
AddRelocation<ELF>(0xd1ce0004, 0x11, 0, &relocations);
AddRelocation<ELF>(0xd1ce0008, 0x11, 0, &relocations);
// Three more relocations, 8 byte deltas.
AddRelocation<ELF>(0xd1ce0010, 0x11, 0, &relocations);
AddRelocation<ELF>(0xd1ce0018, 0x11, 0, &relocations);
AddRelocation<ELF>(0xd1ce0020, 0x11, 0, &relocations);
RelocationPacker<ELF> packer;
packed.clear();
packer.PackRelocations(relocations, &packed);
ASSERT_EQ(18U, packed.size());
// Identifier.
size_t ndx = 0;
EXPECT_EQ('A', packed[ndx++]);
EXPECT_EQ('P', packed[ndx++]);
EXPECT_EQ('S', packed[ndx++]);
EXPECT_EQ('2', packed[ndx++]);
// relocation count
EXPECT_EQ(6, packed[ndx++]);
// base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit)
EXPECT_EQ(0xfc, packed[ndx++]);
EXPECT_EQ(0xff, packed[ndx++]);
EXPECT_EQ(0xb7, packed[ndx++]);
EXPECT_EQ(0x8e, packed[ndx++]);
EXPECT_EQ(is_32 ? 0x7d : 0x0d, packed[ndx++]);
// first group
EXPECT_EQ(3, packed[ndx++]); // size
EXPECT_EQ(3, packed[ndx++]); // flags
EXPECT_EQ(4, packed[ndx++]); // r_offset_delta
EXPECT_EQ(0x11, packed[ndx++]); // r_info
// second group
EXPECT_EQ(3, packed[ndx++]); // size
EXPECT_EQ(3, packed[ndx++]); // flags
EXPECT_EQ(8, packed[ndx++]); // r_offset_delta
EXPECT_EQ(0x11, packed[ndx++]); // r_info
EXPECT_EQ(ndx, packed.size());
}
TEST(Packer, PackNoAddend32) {
DoPackNoAddend<ELF32_traits>();
}
TEST(Packer, PackNoAddend64) {
DoPackNoAddend<ELF64_traits>();
}
template <typename ELF>
static void DoUnpackNoAddend() {
std::vector<typename ELF::Rela> relocations;
std::vector<uint8_t> packed;
bool is_32 = sizeof(typename ELF::Addr) == 4;
packed.push_back('A');
packed.push_back('P');
packed.push_back('S');
packed.push_back('2');
// relocation count
packed.push_back(6);
// base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 7d/0d (32/64bit)
packed.push_back(0xfc);
packed.push_back(0xff);
packed.push_back(0xb7);
packed.push_back(0x8e);
packed.push_back(is_32 ? 0x7d : 0x0d);
// first group
packed.push_back(3); // size
packed.push_back(3); // flags
packed.push_back(4); // r_offset_delta
packed.push_back(0x11); // r_info
// second group
packed.push_back(3); // size
packed.push_back(3); // flags
packed.push_back(8); // r_offset_delta
packed.push_back(0x11); // r_info
RelocationPacker<ELF> packer;
packer.UnpackRelocations(packed, &relocations);
size_t ndx = 0;
EXPECT_EQ(6U, relocations.size());
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x11, 0, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x11, 0, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x11, 0, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x11, 0, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x11, 0, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x11, 0, relocations[ndx++]));
EXPECT_EQ(ndx, relocations.size());
}
TEST(Packer, UnpackNoAddend32) {
DoUnpackNoAddend<ELF32_traits>();
}
TEST(Packer, UnpackNoAddend64) {
DoUnpackNoAddend<ELF64_traits>();
}
template <typename ELF>
static void DoPackWithAddend() {
std::vector<typename ELF::Rela> relocations;
// Initial relocation.
AddRelocation<ELF>(0xd1ce0000, 0x01, 10024, &relocations);
// Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
AddRelocation<ELF>(0xd1ce0004, 0x01, 10012, &relocations);
AddRelocation<ELF>(0xd1ce0008, 0x01, 10024, &relocations);
// Three more relocations, 8 byte deltas, -24 byte addend deltas.
AddRelocation<ELF>(0xd1ce0010, 0x01, 10000, &relocations);
AddRelocation<ELF>(0xd1ce0018, 0x01, 9976, &relocations);
AddRelocation<ELF>(0xd1ce0020, 0x01, 9952, &relocations);
std::vector<uint8_t> packed;
RelocationPacker<ELF> packer;
packed.clear();
packer.PackRelocations(relocations, &packed);
EXPECT_EQ(26U, packed.size());
size_t ndx = 0;
// Identifier.
EXPECT_EQ('A', packed[ndx++]);
EXPECT_EQ('P', packed[ndx++]);
EXPECT_EQ('S', packed[ndx++]);
EXPECT_EQ('2', packed[ndx++]);
// Relocation count
EXPECT_EQ(6U, packed[ndx++]);
// base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d/7d (depending on ELF::Addr)
EXPECT_EQ(0xfc, packed[ndx++]);
EXPECT_EQ(0xff, packed[ndx++]);
EXPECT_EQ(0xb7, packed[ndx++]);
EXPECT_EQ(0x8e, packed[ndx++]);
if (sizeof(typename ELF::Addr) == 8) {
// positive for uint64_t
EXPECT_EQ(0x0d, packed[ndx++]);
} else {
// negative for uint32_t
EXPECT_EQ(0x7d, packed[ndx++]);
}
// group 1
EXPECT_EQ(0x03, packed[ndx++]); // size
EXPECT_EQ(0x0b, packed[ndx++]); // flags
EXPECT_EQ(0x04, packed[ndx++]); // r_offset_delta
EXPECT_EQ(0x01, packed[ndx++]); // r_info
// group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
EXPECT_EQ(0xa8, packed[ndx++]);
EXPECT_EQ(0xce, packed[ndx++]);
EXPECT_EQ(0x00, packed[ndx++]);
// group 1 - addend 2: -12 = 0x74
EXPECT_EQ(0x74, packed[ndx++]);
// group 1 - addend 3: +12 = 0x0c
EXPECT_EQ(0x0c, packed[ndx++]);
// group 2
EXPECT_EQ(0x03, packed[ndx++]); // size
EXPECT_EQ(0x0b, packed[ndx++]); // flags
EXPECT_EQ(0x08, packed[ndx++]); // r_offset_delta
EXPECT_EQ(0x01, packed[ndx++]); // r_info
// group 2 - addend 1: -24 = 0x68
EXPECT_EQ(0x68, packed[ndx++]);
// group 2 - addend 2: -24 = 0x68
EXPECT_EQ(0x68, packed[ndx++]);
// group 2 - addend 3: -24 = 0x68
EXPECT_EQ(0x68, packed[ndx++]);
EXPECT_EQ(ndx, packed.size());
}
TEST(Packer, PackWithAddend) {
DoPackWithAddend<ELF32_traits>();
DoPackWithAddend<ELF64_traits>();
}
template <typename ELF>
static void DoUnpackWithAddend() {
std::vector<uint8_t> packed;
// Identifier.
packed.push_back('A');
packed.push_back('P');
packed.push_back('S');
packed.push_back('2');
// Relocation count
packed.push_back(6U);
// base relocation = 0xd1cdfffc -> fc, ff, b7, 8e, 0d
packed.push_back(0xfc);
packed.push_back(0xff);
packed.push_back(0xb7);
packed.push_back(0x8e);
if (sizeof(typename ELF::Addr) == 8) {
// positive for uint64_t
packed.push_back(0x0d);
} else {
// negative for uint32_t
packed.push_back(0x7d);
}
// group 1
packed.push_back(0x03); // size
packed.push_back(0x0b); // flags
packed.push_back(0x04); // r_offset_delta
packed.push_back(0x01); // r_info
// group 1 - addend 1: 10024 = 0xa8, 0xce, 0x80
packed.push_back(0xa8);
packed.push_back(0xce);
packed.push_back(0x00);
// group 1 - addend 2: -12 = 0x74
packed.push_back(0x74);
// group 1 - addend 3: +12 = 0x0c
packed.push_back(0x0c);
// group 2
packed.push_back(0x03); // size
packed.push_back(0x0b); // flags
packed.push_back(0x08); // r_offset_delta
packed.push_back(0x01); // r_info
// group 2 - addend 1: -24 = 0x68
packed.push_back(0x68);
// group 2 - addend 2: -24 = 0x68
packed.push_back(0x68);
// group 2 - addend 3: -24 = 0x68
packed.push_back(0x68);
std::vector<typename ELF::Rela> relocations;
RelocationPacker<ELF> packer;
relocations.clear();
packer.UnpackRelocations(packed, &relocations);
EXPECT_EQ(6U, relocations.size());
size_t ndx = 0;
// Initial relocation.
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0000, 0x01, 10024, relocations[ndx++]));
// Two more relocations, 4 byte offset deltas, 12 byte addend deltas.
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0004, 0x01, 10012, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0008, 0x01, 10024, relocations[ndx++]));
// Three more relocations, 8 byte offset deltas, -24 byte addend deltas.
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0010, 0x01, 10000, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0018, 0x01, 9976, relocations[ndx++]));
EXPECT_TRUE(CheckRelocation<ELF>(0xd1ce0020, 0x01, 9952, relocations[ndx++]));
EXPECT_EQ(ndx, relocations.size());
}
TEST(Packer, UnpackWithAddend) {
DoUnpackWithAddend<ELF32_traits>();
DoUnpackWithAddend<ELF64_traits>();
}
} // namespace relocation_packer

View File

@ -0,0 +1,10 @@
// Copyright 2014 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.
#include "testing/gtest/include/gtest/gtest.h"
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,131 @@
// Copyright 2014 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.
#include "sleb128.h"
#include <limits.h>
#include <stdint.h>
#include <vector>
#include "elf_traits.h"
namespace {
template <typename T>
class uint_traits {};
template <>
class uint_traits<uint64_t> {
public:
typedef int64_t int_t;
};
template <>
class uint_traits<uint32_t> {
public:
typedef int32_t int_t;
};
}
namespace relocation_packer {
// Empty constructor and destructor to silence chromium-style.
template <typename uint_t>
Sleb128Encoder<uint_t>::Sleb128Encoder() { }
template <typename uint_t>
Sleb128Encoder<uint_t>::~Sleb128Encoder() { }
// Add a single value to the encoding. Values are encoded with variable
// length. The least significant 7 bits of each byte hold 7 bits of data,
// and the most significant bit is set on each byte except the last. The
// value is sign extended up to a multiple of 7 bits (ensuring that the
// most significant bit is zero for a positive number and one for a
// negative number).
template <typename uint_t>
void Sleb128Encoder<uint_t>::Enqueue(uint_t value) {
typedef typename uint_traits<uint_t>::int_t int_t;
static const size_t size = CHAR_BIT * sizeof(value);
bool more = true;
const bool negative = static_cast<int_t>(value) < 0;
while (more) {
uint8_t byte = value & 127;
value >>= 7;
// Sign extend if encoding a -ve value.
if (negative)
value |= -(static_cast<uint_t>(1) << (size - 7));
// The sign bit of byte is second high order bit.
const bool sign_bit = byte & 64;
if ((value == 0 && !sign_bit) || (value == static_cast<uint_t>(-1) && sign_bit))
more = false;
else
byte |= 128;
encoding_.push_back(byte);
}
}
// Add a vector of values to the encoding.
template <typename uint_t>
void Sleb128Encoder<uint_t>::EnqueueAll(const std::vector<uint_t>& values) {
for (size_t i = 0; i < values.size(); ++i) {
Enqueue(values[i]);
}
}
// Create a new decoder for the given encoded stream.
template <typename uint_t>
Sleb128Decoder<uint_t>::Sleb128Decoder(const std::vector<uint8_t>& encoding, size_t start_with) {
encoding_ = encoding;
cursor_ = start_with;
}
// Empty destructor to silence chromium-style.
template <typename uint_t>
Sleb128Decoder<uint_t>::~Sleb128Decoder() { }
// Decode and retrieve a single value from the encoding. Consume bytes
// until one without its most significant bit is found, and re-form the
// value from the 7 bit fields of the bytes consumed.
template <typename uint_t>
uint_t Sleb128Decoder<uint_t>::Dequeue() {
uint_t value = 0;
static const size_t size = CHAR_BIT * sizeof(value);
size_t shift = 0;
uint8_t byte;
// Loop until we reach a byte with its high order bit clear.
do {
byte = encoding_[cursor_++];
value |= (static_cast<uint_t>(byte & 127) << shift);
shift += 7;
} while (byte & 128);
// The sign bit is second high order bit of the final byte decoded.
// Sign extend if value is -ve and we did not shift all of it.
if (shift < size && (byte & 64))
value |= -(static_cast<uint_t>(1) << shift);
return static_cast<uint_t>(value);
}
// Decode and retrieve all remaining values from the encoding.
template <typename uint_t>
void Sleb128Decoder<uint_t>::DequeueAll(std::vector<uint_t>* values) {
while (cursor_ < encoding_.size()) {
values->push_back(Dequeue());
}
}
template class Sleb128Encoder<uint32_t>;
template class Sleb128Encoder<uint64_t>;
template class Sleb128Decoder<uint32_t>;
template class Sleb128Decoder<uint64_t>;
} // namespace relocation_packer

View File

@ -0,0 +1,76 @@
// Copyright 2014 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.
// SLEB128 encoder and decoder for packed relative relocations.
//
// Packed relocations consist of a large number of relatively small
// integer values. Encoding these as LEB128 saves space.
//
// For more on LEB128 see http://en.wikipedia.org/wiki/LEB128.
#ifndef TOOLS_RELOCATION_PACKER_SRC_SLEB128_H_
#define TOOLS_RELOCATION_PACKER_SRC_SLEB128_H_
#include <stdint.h>
#include <unistd.h>
#include <vector>
#include "elf_traits.h"
namespace relocation_packer {
// Encode packed words as a signed LEB128 byte stream.
template<typename int_t>
class Sleb128Encoder {
public:
// Explicit (but empty) constructor and destructor, for chromium-style.
Sleb128Encoder();
~Sleb128Encoder();
// Add a value to the encoding stream.
// |value| is the signed int to add.
void Enqueue(int_t value);
// Add a vector of values to the encoding stream.
// |values| is the vector of signed ints to add.
void EnqueueAll(const std::vector<int_t>& values);
// Retrieve the encoded representation of the values.
// |encoding| is the returned vector of encoded data.
void GetEncoding(std::vector<uint8_t>* encoding) { *encoding = encoding_; }
private:
// Growable vector holding the encoded LEB128 stream.
std::vector<uint8_t> encoding_;
};
// Decode a LEB128 byte stream to produce packed words.
template <typename int_t>
class Sleb128Decoder {
public:
// Create a new decoder for the given encoded stream.
// |encoding| is the vector of encoded data.
explicit Sleb128Decoder(const std::vector<uint8_t>& encoding, size_t start_with);
// Explicit (but empty) destructor, for chromium-style.
~Sleb128Decoder();
// Retrieve the next value from the encoded stream.
int_t Dequeue();
// Retrieve all remaining values from the encoded stream.
// |values| is the vector of decoded data.
void DequeueAll(std::vector<int_t>* values);
private:
// Encoded LEB128 stream.
std::vector<uint8_t> encoding_;
// Cursor indicating the current stream retrieval point.
size_t cursor_;
};
} // namespace relocation_packer
#endif // TOOLS_RELOCATION_PACKER_SRC_SLEB128_H_

View File

@ -0,0 +1,166 @@
// Copyright 2014 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.
#include "sleb128.h"
#include <vector>
#include "elf_traits.h"
#include "gtest/gtest.h"
namespace relocation_packer {
TEST(Sleb128, Encoder64) {
std::vector<uint64_t> values;
values.push_back(624485U);
values.push_back(0U);
values.push_back(1U);
values.push_back(63U);
values.push_back(64U);
values.push_back(static_cast<uint64_t>(-1));
values.push_back(static_cast<uint64_t>(-624485));
Sleb128Encoder<uint64_t> encoder;
encoder.EnqueueAll(values);
encoder.Enqueue(2147483647U);
encoder.Enqueue(static_cast<uint64_t>(-2147483648));
encoder.Enqueue(9223372036854775807ULL);
encoder.Enqueue(static_cast<uint64_t>(-9223372036854775807LL - 1));
std::vector<uint8_t> encoding;
encoder.GetEncoding(&encoding);
EXPECT_EQ(42u, encoding.size());
// 624485
EXPECT_EQ(0xe5, encoding[0]);
EXPECT_EQ(0x8e, encoding[1]);
EXPECT_EQ(0x26, encoding[2]);
// 0
EXPECT_EQ(0x00, encoding[3]);
// 1
EXPECT_EQ(0x01, encoding[4]);
// 63
EXPECT_EQ(0x3f, encoding[5]);
// 64
EXPECT_EQ(0xc0, encoding[6]);
EXPECT_EQ(0x00, encoding[7]);
// -1
EXPECT_EQ(0x7f, encoding[8]);
// -624485
EXPECT_EQ(0x9b, encoding[9]);
EXPECT_EQ(0xf1, encoding[10]);
EXPECT_EQ(0x59, encoding[11]);
// 2147483647
EXPECT_EQ(0xff, encoding[12]);
EXPECT_EQ(0xff, encoding[13]);
EXPECT_EQ(0xff, encoding[14]);
EXPECT_EQ(0xff, encoding[15]);
EXPECT_EQ(0x07, encoding[16]);
// -2147483648
EXPECT_EQ(0x80, encoding[17]);
EXPECT_EQ(0x80, encoding[18]);
EXPECT_EQ(0x80, encoding[19]);
EXPECT_EQ(0x80, encoding[20]);
EXPECT_EQ(0x78, encoding[21]);
// 9223372036854775807
EXPECT_EQ(0xff, encoding[22]);
EXPECT_EQ(0xff, encoding[23]);
EXPECT_EQ(0xff, encoding[24]);
EXPECT_EQ(0xff, encoding[25]);
EXPECT_EQ(0xff, encoding[26]);
EXPECT_EQ(0xff, encoding[27]);
EXPECT_EQ(0xff, encoding[28]);
EXPECT_EQ(0xff, encoding[29]);
EXPECT_EQ(0xff, encoding[30]);
EXPECT_EQ(0x00, encoding[31]);
// -9223372036854775808
EXPECT_EQ(0x80, encoding[32]);
EXPECT_EQ(0x80, encoding[33]);
EXPECT_EQ(0x80, encoding[34]);
EXPECT_EQ(0x80, encoding[35]);
EXPECT_EQ(0x80, encoding[36]);
EXPECT_EQ(0x80, encoding[37]);
EXPECT_EQ(0x80, encoding[38]);
EXPECT_EQ(0x80, encoding[39]);
EXPECT_EQ(0x80, encoding[40]);
EXPECT_EQ(0x7f, encoding[41]);
}
TEST(Sleb128, Decoder) {
std::vector<uint8_t> encoding;
// 624485
encoding.push_back(0xe5);
encoding.push_back(0x8e);
encoding.push_back(0x26);
// 0
encoding.push_back(0x00);
// 1
encoding.push_back(0x01);
// 63
encoding.push_back(0x3f);
// 64
encoding.push_back(0xc0);
encoding.push_back(0x00);
// -1
encoding.push_back(0x7f);
// -624485
encoding.push_back(0x9b);
encoding.push_back(0xf1);
encoding.push_back(0x59);
// 2147483647
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0x07);
// -2147483648
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x78);
// 9223372036854775807
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0xff);
encoding.push_back(0x00);
// -9223372036854775808
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x80);
encoding.push_back(0x7f);
Sleb128Decoder<uint64_t> decoder(encoding, 0);
EXPECT_EQ(624485U, decoder.Dequeue());
std::vector<uint64_t> dequeued;
decoder.DequeueAll(&dequeued);
EXPECT_EQ(10U, dequeued.size());
EXPECT_EQ(0U, dequeued[0]);
EXPECT_EQ(1U, dequeued[1]);
EXPECT_EQ(63U, dequeued[2]);
EXPECT_EQ(64U, dequeued[3]);
EXPECT_EQ(static_cast<uint64_t>(-1), dequeued[4]);
EXPECT_EQ(static_cast<uint64_t>(-624485), dequeued[5]);
EXPECT_EQ(2147483647U, dequeued[6]);
EXPECT_EQ(static_cast<uint64_t>(-2147483648), dequeued[7]);
EXPECT_EQ(9223372036854775807ULL, dequeued[8]);
EXPECT_EQ(static_cast<uint64_t>(-9223372036854775807LL - 1), dequeued[9]);
}
} // namespace relocation_packer

View File

@ -0,0 +1,9 @@
# Copyright 2015 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.
relocation_packer_target =
"//third_party/android_platform:android_relocation_packer($host_toolchain)"
relocation_packer_dir =
get_label_info("$relocation_packer_target", "root_out_dir")
relocation_packer_exe = "${relocation_packer_dir}/android_relocation_packer"

View File

@ -0,0 +1,320 @@
<code_scheme name="AndroidStyle">
<option name="JAVA_INDENT_OPTIONS">
<value>
<option name="INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="8" />
<option name="TAB_SIZE" value="8" />
<option name="USE_TAB_CHARACTER" value="false" />
<option name="SMART_TABS" value="false" />
<option name="LABEL_INDENT_SIZE" value="0" />
<option name="LABEL_INDENT_ABSOLUTE" value="false" />
<option name="USE_RELATIVE_INDENTS" value="false" />
</value>
</option>
<option name="FIELD_NAME_PREFIX" value="m" />
<option name="STATIC_FIELD_NAME_PREFIX" value="s" />
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="9999" />
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="true" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="true" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="true" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="true" />
<emptyLine />
<package name="com" withSubpackages="true" static="true" />
<emptyLine />
<package name="gov" withSubpackages="true" static="true" />
<emptyLine />
<package name="junit" withSubpackages="true" static="true" />
<emptyLine />
<package name="net" withSubpackages="true" static="true" />
<emptyLine />
<package name="org" withSubpackages="true" static="true" />
<emptyLine />
<package name="java" withSubpackages="true" static="true" />
<emptyLine />
<package name="javax" withSubpackages="true" static="true" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com.android" withSubpackages="true" static="false" />
<emptyLine />
<package name="dalvik" withSubpackages="true" static="false" />
<emptyLine />
<package name="libcore" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="gov" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<option name="JD_P_AT_EMPTY_LINES" value="false" />
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
<option name="JD_PRESERVE_LINE_FEEDS" value="true" />
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<ADDITIONAL_INDENT_OPTIONS fileType="java">
<option name="TAB_SIZE" value="8" />
</ADDITIONAL_INDENT_OPTIONS>
<ADDITIONAL_INDENT_OPTIONS fileType="js">
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</ADDITIONAL_INDENT_OPTIONS>
<codeStyleSettings language="JAVA">
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="PREFER_PARAMETERS_WRAP" value="true" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="RESOURCE_LIST_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="DOWHILE_BRACE_FORCE" value="1" />
<option name="WHILE_BRACE_FORCE" value="1" />
<option name="FOR_BRACE_FORCE" value="1" />
<option name="WRAP_LONG_LINES" value="true" />
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
<option name="BLANK_LINES_AROUND_FIELD" value="1" />
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="ALIGN_MULTILINE_FOR" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="1" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="1" />
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
<option name="TERNARY_OPERATION_WRAP" value="1" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="1" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE" value="true" />
<option name="WRAP_COMMENTS" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>

View File

@ -0,0 +1,8 @@
#! /bin/bash
# Copyright 2017 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.
base_dir=$(dirname "$0")
exec python "$base_dir/stack.py" "$@"

View File

@ -0,0 +1,250 @@
#!/usr/bin/env python
#
# Copyright (C) 2013 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.
"""stack symbolizes native crash dumps."""
import getopt
import glob
import logging
import os
import sys
import stack_core
import stack_libs
import subprocess
import symbol
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir, os.pardir,
'build', 'android'))
from pylib import constants
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir, os.pardir,
'tools', 'python'))
import llvm_symbolizer
DEFAULT_SYMROOT='/tmp/symbols'
# From: https://source.android.com/source/build-numbers.html
_ANDROID_M_MAJOR_VERSION=6
def PrintUsage():
"""Print usage and exit with error."""
# pylint: disable-msg=C6310
print
print " usage: " + sys.argv[0] + " [options] [FILE]"
print
print " --symbols-dir=path"
print " the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols"
print
print " --chrome-symbols-dir=path"
print " the path to a Chrome symbols dir (can be absolute or relative"
print " to src), such as =out/Debug/lib.unstripped"
print
print " --output-directory=path"
print " the path to the build output directory, such as out/Debug."
print " Ignored if --chrome-symbols-dir is passed."
print
print " --packed-relocation-adjustments"
print " --no-packed-relocation-adjustments"
print " turn packed relocation adjustment on and off (default is off)"
print " If running on pre-M Android and the stack trace appears to"
print " make no sense, try turning this feature on."
print
print " --symbols-zip=path"
print " the path to a symbols zip file, such as =dream-symbols-12345.zip"
print
print " --more-info"
print " --less-info"
print " Change the level of detail in the output."
print " --more-info is slower and more verbose, but more functions will"
print " be fully qualified with namespace/classname and have full"
print " argument information. Also, the 'stack data' section will be"
print " printed."
print
print " --arch=arm|arm64|x64|x86|mips"
print " the target architecture"
print
print " --fallback-monochrome"
print " fallback to monochrome instead of chrome if fail to detect"
print " shared lib which is loaded from APK, this doesn't work for"
print " component build."
print
print " --verbose"
print " enable extra logging, particularly for debugging failed symbolization"
print
print " FILE should contain a stack trace in it somewhere"
print " the tool will find that and re-print it with"
print " source files and line numbers. If you don't"
print " pass FILE, or if file is -, it reads from"
print " stdin."
print
# pylint: enable-msg=C6310
sys.exit(1)
def UnzipSymbols(symbolfile, symdir=None):
"""Unzips a file to DEFAULT_SYMROOT and returns the unzipped location.
Args:
symbolfile: The .zip file to unzip
symdir: Optional temporary directory to use for extraction
Returns:
A tuple containing (the directory into which the zip file was unzipped,
the path to the "symbols" directory in the unzipped file). To clean
up, the caller can delete the first element of the tuple.
Raises:
SymbolDownloadException: When the unzip fails.
"""
if not symdir:
symdir = "%s/%s" % (DEFAULT_SYMROOT, hash(symbolfile))
if not os.path.exists(symdir):
os.makedirs(symdir)
print "extracting %s..." % symbolfile
saveddir = os.getcwd()
os.chdir(symdir)
try:
unzipcode = subprocess.call(["unzip", "-qq", "-o", symbolfile])
if unzipcode > 0:
os.remove(symbolfile)
raise SymbolDownloadException("failed to extract symbol files (%s)."
% symbolfile)
finally:
os.chdir(saveddir)
android_symbols = glob.glob("%s/out/target/product/*/symbols" % symdir)
if android_symbols:
return (symdir, android_symbols[0])
else:
# This is a zip of Chrome symbols, so symbol.CHROME_SYMBOLS_DIR needs to be
# updated to point here.
symbol.CHROME_SYMBOLS_DIR = symdir
return (symdir, symdir)
def main(argv):
try:
options, arguments = getopt.getopt(argv, "",
["packed-relocation-adjustments",
"no-packed-relocation-adjustments",
"more-info",
"less-info",
"chrome-symbols-dir=",
"output-directory=",
"symbols-dir=",
"symbols-zip=",
"packed-lib=",
"arch=",
"fallback-monochrome",
"verbose",
"help"])
except getopt.GetoptError, unused_error:
PrintUsage()
zip_arg = None
more_info = False
fallback_monochrome = False
arch_defined = False
packed_libs = []
for option, value in options:
if option == "--help":
PrintUsage()
elif option == "--symbols-dir":
symbol.SYMBOLS_DIR = os.path.expanduser(value)
elif option == "--symbols-zip":
zip_arg = os.path.expanduser(value)
elif option == "--arch":
symbol.ARCH = value
arch_defined = True
elif option == "--chrome-symbols-dir":
symbol.CHROME_SYMBOLS_DIR = os.path.join(constants.DIR_SOURCE_ROOT,
value)
elif option == "--output-directory":
constants.SetOutputDirectory(value)
elif option == "--packed-lib":
packed_libs.append(os.path.expanduser(value))
elif option == "--more-info":
more_info = True
elif option == "--less-info":
more_info = False
elif option == "--fallback-monochrome":
fallback_monochrome = True
elif option == "--verbose":
logging.basicConfig(level=logging.DEBUG)
elif option in (
'--packed-relocation-adjustments',
'--no-packed-relocation-adjustments'):
print ('--[no-]packed-relocation-adjustments options are deprecated. '
'Specify packed libs directory instead.')
if len(arguments) > 1:
PrintUsage()
# Do an up-front test that the output directory is known.
if not symbol.CHROME_SYMBOLS_DIR:
constants.CheckOutputDirectory()
if not arguments or arguments[0] == "-":
print "Reading native crash info from stdin"
f = sys.stdin
else:
print "Searching for native crashes in: " + os.path.realpath(arguments[0])
f = open(arguments[0], "r")
lines = f.readlines()
f.close()
rootdir = None
if zip_arg:
rootdir, symbol.SYMBOLS_DIR = UnzipSymbols(zip_arg)
version = stack_libs.GetTargetAndroidVersionNumber(lines)
if version is None:
print ("Unknown Android release, "
"consider passing --packed-lib.")
elif version < _ANDROID_M_MAJOR_VERSION and not packed_libs:
print ("Pre-M Android release detected, "
"but --packed-lib not specified. Stack symbolization may fail.")
if (version is None or version < _ANDROID_M_MAJOR_VERSION) and packed_libs:
load_vaddrs = stack_libs.GetLoadVaddrs(stripped_libs=packed_libs)
else:
load_vaddrs = {}
print ("Reading Android symbols from: "
+ os.path.normpath(symbol.SYMBOLS_DIR))
chrome_search_path = symbol.GetLibrarySearchPaths()
with llvm_symbolizer.LLVMSymbolizer() as symbolizer:
print ("Searching for Chrome symbols from within: "
+ ':'.join((os.path.normpath(d) for d in chrome_search_path)))
stack_core.ConvertTrace(lines, load_vaddrs, more_info, fallback_monochrome,
arch_defined, symbolizer)
if rootdir:
# be a good citizen and clean up...os.rmdir and os.removedirs() don't work
cmd = "rm -rf \"%s\"" % rootdir
print "\ncleaning up (%s)" % cmd
os.system(cmd)
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
# vi: ts=2 sw=2

View File

@ -0,0 +1,548 @@
#!/usr/bin/env python
#
# Copyright (C) 2013 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.
"""stack symbolizes native crash dumps."""
import itertools
import logging
import multiprocessing
import os
import re
import struct
import subprocess
import time
import zipfile
import symbol
from pylib import constants
UNKNOWN = '<unknown>'
HEAP = '[heap]'
STACK = '[stack]'
_DEFAULT_JOBS=8
_CHUNK_SIZE = 1000
_BASE_APK = 'base.apk'
_FALLBACK_SO = 'libchrome.so'
_ABI_LINE = re.compile('ABI: \'(?P<abi>[a-z0-9A-Z]+)\'')
_PROCESS_INFO_LINE = re.compile('(pid: [0-9]+, tid: [0-9]+.*)')
# Same as above, but used to extract the pid.
_PROCESS_INFO_PID = re.compile('pid: ([0-9]+)')
_SIGNAL_LINE = re.compile('(signal [0-9]+ \(.*\).*)')
_REGISTER_LINE = re.compile('(([ ]*[0-9a-z]{2} [0-9a-f]{8}){4})')
_THREAD_LINE = re.compile('(.*)(\-\-\- ){15}\-\-\-')
_DALVIK_JNI_THREAD_LINE = re.compile("(\".*\" prio=[0-9]+ tid=[0-9]+ NATIVE.*)")
_DALVIK_NATIVE_THREAD_LINE = re.compile("(\".*\" sysTid=[0-9]+ nice=[0-9]+.*)")
_JAVA_STDERR_LINE = re.compile("([0-9]+)\s+[0-9]+\s+.\s+System.err:\s*(.+)")
_WIDTH = '{8}'
# Matches LOG(FATAL) lines, like the following example:
# [FATAL:source_file.cc(33)] Check failed: !instances_.empty()
_LOG_FATAL_LINE = re.compile('(\[FATAL\:.*\].*)$')
# Note that both trace and value line matching allow for variable amounts of
# whitespace (e.g. \t). This is because the we want to allow for the stack
# tool to operate on AndroidFeedback provided system logs. AndroidFeedback
# strips out double spaces that are found in tombsone files and logcat output.
#
# Examples of matched trace lines include lines from tombstone files like:
# #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
# #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so (symbol)
# Or lines from AndroidFeedback crash report system logs like:
# 03-25 00:51:05.520 I/DEBUG ( 65): #00 pc 001cf42e /data/data/com.my.project/lib/libmyproject.so
# Please note the spacing differences.
_TRACE_LINE = re.compile('(.*)\#(?P<frame>[0-9]+)[ \t]+(..)[ \t]+(0x)?(?P<address>[0-9a-f]{0,16})[ \t]+(?P<lib>[^\r\n \t]*)(?P<symbol_present> \((?P<symbol_name>.*)\))?') # pylint: disable-msg=C6310
def InitWidthRelatedLineMatchers():
global _WIDTH
global _DEBUG_TRACE_LINE, _VALUE_LINE, _CODE_LINE
if symbol.ARCH == 'arm64' or symbol.ARCH == 'x86_64' or symbol.ARCH == 'x64':
_WIDTH = '{16}'
# Matches lines emitted by src/base/debug/stack_trace_android.cc, like:
# #00 0x7324d92d /data/app-lib/org.chromium.native_test-1/libbase.cr.so+0x0006992d
# This pattern includes the unused named capture groups <symbol_present> and
# <symbol_name> so that it can interoperate with the |_TRACE_LINE| regex.
_DEBUG_TRACE_LINE = re.compile(
'(.*)(?P<frame>\#[0-9]+ 0x[0-9a-f]' + _WIDTH + ') '
'(?P<lib>[^+]+)\+0x(?P<address>[0-9a-f]' + _WIDTH + ')'
'(?P<symbol_present>)(?P<symbol_name>)')
# Examples of matched value lines include:
# bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
# bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so (symbol)
# 03-25 00:51:05.530 I/DEBUG ( 65): bea4170c 8018e4e9 /data/data/com.my.project/lib/libmyproject.so
# Again, note the spacing differences.
_VALUE_LINE = re.compile('(.*)([0-9a-f]' + _WIDTH + ')[ \t]+([0-9a-f]' + _WIDTH + ')[ \t]+([^\r\n \t]*)( \((.*)\))?')
# Lines from 'code around' sections of the output will be matched before
# value lines because otheriwse the 'code around' sections will be confused as
# value lines.
#
# Examples include:
# 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
# 03-25 00:51:05.530 I/DEBUG ( 65): 801cf40c ffffc4cc 00b2f2c5 00b2f1c7 00c1e1a8
_CODE_LINE = re.compile('(.*)[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[a-f0-9]' + _WIDTH +
'[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[a-f0-9]' + _WIDTH +
'[ \t]*[a-f0-9]' + _WIDTH + '[ \t]*[ \r\n]') # pylint: disable-msg=C6310
# This pattern is used to find shared library offset in APK.
# Example:
# (offset 0x568000)
_SHARED_LIB_OFFSET_IN_APK = re.compile(' \(offset 0x(?P<offset>[0-9a-f]{0,16})\)$')
def PrintTraceLines(trace_lines):
"""Print back trace."""
maxlen = max(map(lambda tl: len(tl[1]), trace_lines))
print
print 'Stack Trace:'
print ' RELADDR ' + 'FUNCTION'.ljust(maxlen) + ' FILE:LINE'
for tl in trace_lines:
(addr, symbol_with_offset, location) = tl
normalized = os.path.normpath(location)
print ' %8s %s %s' % (addr, symbol_with_offset.ljust(maxlen), normalized)
return
def PrintValueLines(value_lines):
"""Print stack data values."""
maxlen = max(map(lambda tl: len(tl[2]), value_lines))
print
print 'Stack Data:'
print ' ADDR VALUE ' + 'FUNCTION'.ljust(maxlen) + ' FILE:LINE'
for vl in value_lines:
(addr, value, symbol_with_offset, location) = vl
print ' %8s %8s %s %s' % (addr, value, symbol_with_offset.ljust(maxlen), location)
return
def PrintJavaLines(java_lines):
"""Print java stderr lines."""
print
print 'Java stderr from crashing pid (may identify underlying Java exception):'
for l in java_lines:
if l.startswith('at'):
print ' ',
print l
def PrintOutput(trace_lines, value_lines, java_lines, more_info):
if trace_lines:
PrintTraceLines(trace_lines)
if value_lines:
# TODO(cjhopman): it seems that symbol.SymbolInformation always fails to
# find information for addresses in value_lines in chrome libraries, and so
# value_lines have little value to us and merely clutter the output.
# Since information is sometimes contained in these lines (from system
# libraries), don't completely disable them.
if more_info:
PrintValueLines(value_lines)
if java_lines:
PrintJavaLines(java_lines)
def PrintDivider():
print
print '-----------------------------------------------------\n'
def ConvertTrace(lines, load_vaddrs, more_info, fallback_monochrome, arch_defined, llvm_symbolizer):
"""Convert strings containing native crash to a stack."""
InitWidthRelatedLineMatchers()
if fallback_monochrome:
global _FALLBACK_SO
_FALLBACK_SO = 'libmonochrome.so'
start = time.time()
chunks = [lines[i: i+_CHUNK_SIZE] for i in xrange(0, len(lines), _CHUNK_SIZE)]
pool = multiprocessing.Pool(processes=_DEFAULT_JOBS)
results = pool.map(PreProcessLog(load_vaddrs), chunks)
useful_log = []
so_dirs = []
for result in results:
useful_log += result[0]
so_dirs += result[1]
pool.close()
pool.join()
end = time.time()
logging.debug('Finished processing. Elapsed time: %.4fs', (end - start))
if so_dirs:
UpdateLibrarySearchPath(so_dirs)
# if arch isn't defined in command line, find it from log
if not arch_defined:
arch = _FindAbi(useful_log)
if arch:
print ('Find ABI:' + arch)
symbol.ARCH = arch
ResolveCrashSymbol(list(useful_log), more_info, llvm_symbolizer)
end = time.time()
logging.debug('Finished resolving symbols. Elapsed time: %.4fs',
(end - start))
class PreProcessLog:
"""Closure wrapper, for multiprocessing.Pool.map."""
def __init__(self, load_vaddrs):
"""Bind load_vaddrs to the PreProcessLog closure.
Args:
load_vaddrs: LOAD segment min_vaddrs keyed on mapped executable
"""
self._load_vaddrs = load_vaddrs;
# This is mapping from apk's offset to shared libraries.
self._shared_libraries_mapping = dict()
# The list of directires in which instead of default output dir,
# the shared libraries is found.
self._so_dirs = []
def _DetectSharedLibrary(self, lib, symbol_present):
"""Detect the possible shared library from the mapping offset of APK
Return:
the shared library in APK if only one is found.
"""
offset_match = _SHARED_LIB_OFFSET_IN_APK.match(symbol_present)
if not offset_match:
return
offset = offset_match.group('offset')
key = '%s:%s' % (lib, offset)
if self._shared_libraries_mapping.has_key(key):
soname = self._shared_libraries_mapping[key]
else:
soname, host_so = _FindSharedLibraryFromAPKs(constants.GetOutDirectory(),
int(offset, 16))
if soname:
self._shared_libraries_mapping[key] = soname
so_dir = os.path.dirname(host_so)
# Store the directory if it is not the default output dir, so
# we can update library search path in main process.
if not os.path.samefile(constants.GetOutDirectory(), so_dir):
self._so_dirs.append(so_dir)
print ("Detected: %s is %s which is loaded directly from APK."
% (host_so, soname))
return soname
def _AdjustAddress(self, address, lib):
"""Add the vaddr of the library's first LOAD segment to address.
Args:
address: symbol address as a hexadecimal string
lib: path to loaded library
Returns:
address+load_vaddrs[key] if lib ends with /key, otherwise address
"""
for key, offset in self._load_vaddrs.iteritems():
if lib.endswith('/' + key):
# Add offset to address, and return the result as a hexadecimal string
# with the same number of digits as the original. This allows the
# caller to make a direct textual substitution.
return ('%%0%dx' % len(address)) % (int(address, 16) + offset)
return address
def __call__(self, lines):
"""Preprocess the strings, only keep the useful ones.
Args:
lines: a list of byte strings read from logcat
Returns:
A list of unicode strings related to native crash
"""
useful_log = []
for ln in lines:
line = unicode(ln, errors='ignore')
if (_PROCESS_INFO_LINE.search(line)
or _SIGNAL_LINE.search(line)
or _REGISTER_LINE.search(line)
or _THREAD_LINE.search(line)
or _DALVIK_JNI_THREAD_LINE.search(line)
or _DALVIK_NATIVE_THREAD_LINE.search(line)
or _LOG_FATAL_LINE.search(line)
or _DEBUG_TRACE_LINE.search(line)
or _ABI_LINE.search(line)
or _JAVA_STDERR_LINE.search(line)):
useful_log.append(line)
continue
match = _TRACE_LINE.match(line)
if match:
lib, symbol_present = match.group('lib', 'symbol_present')
if os.path.splitext(lib)[1] == '.apk' and symbol_present:
soname = self._DetectSharedLibrary(lib, symbol_present)
if soname:
line = line.replace('/' + os.path.basename(lib), '/' + soname)
else:
# If the trace line suggests a direct load from APK, replace the
# APK name with _FALLBACK_SO.
line = line.replace('/' + _BASE_APK, '/' + _FALLBACK_SO)
logging.debug("Can't detect shared library in APK, fallback to" +
" library " + _FALLBACK_SO)
# For trace lines specifically, the address may need to be adjusted
# to account for relocation packing. This is because debuggerd on
# pre-M platforms does not understand non-zero vaddr LOAD segments.
address, lib = match.group('address', 'lib')
adjusted_address = self._AdjustAddress(address, lib)
useful_log.append(line.replace(address, adjusted_address, 1))
continue
if _CODE_LINE.match(line):
# Code lines should be ignored. If this were excluded the 'code around'
# sections would trigger value_line matches.
continue
if _VALUE_LINE.match(line):
useful_log.append(line)
return useful_log, self._so_dirs
def ResolveCrashSymbol(lines, more_info, llvm_symbolizer):
"""Convert unicode strings which contains native crash to a stack
"""
trace_lines = []
value_lines = []
last_frame = -1
pid = -1
# Collects all java exception lines, keyed by pid for later output during
# native crash handling.
java_stderr_by_pid = {}
for line in lines:
java_stderr_match = _JAVA_STDERR_LINE.search(line)
if java_stderr_match:
pid, msg = java_stderr_match.groups()
java_stderr_by_pid.setdefault(pid, []).append(msg)
for line in lines:
# AndroidFeedback adds zero width spaces into its crash reports. These
# should be removed or the regular expresssions will fail to match.
process_header = _PROCESS_INFO_LINE.search(line)
signal_header = _SIGNAL_LINE.search(line)
register_header = _REGISTER_LINE.search(line)
thread_header = _THREAD_LINE.search(line)
dalvik_jni_thread_header = _DALVIK_JNI_THREAD_LINE.search(line)
dalvik_native_thread_header = _DALVIK_NATIVE_THREAD_LINE.search(line)
log_fatal_header = _LOG_FATAL_LINE.search(line)
if (process_header or signal_header or register_header or thread_header or
dalvik_jni_thread_header or dalvik_native_thread_header or
log_fatal_header) :
if trace_lines or value_lines:
java_lines = []
if pid != -1 and pid in java_stderr_by_pid:
java_lines = java_stderr_by_pid[pid]
PrintOutput(trace_lines, value_lines, java_lines, more_info)
PrintDivider()
trace_lines = []
value_lines = []
last_frame = -1
pid = -1
if process_header:
# Track the last reported pid to find java exceptions.
pid = _PROCESS_INFO_PID.search(process_header.group(1)).group(1)
print process_header.group(1)
if signal_header:
print signal_header.group(1)
if register_header:
print register_header.group(1)
if thread_header:
print thread_header.group(1)
if dalvik_jni_thread_header:
print dalvik_jni_thread_header.group(1)
if dalvik_native_thread_header:
print dalvik_native_thread_header.group(1)
if log_fatal_header:
print log_fatal_header.group(1)
continue
match = _TRACE_LINE.match(line) or _DEBUG_TRACE_LINE.match(line)
if match:
frame, code_addr, area, symbol_present, symbol_name = match.group(
'frame', 'address', 'lib', 'symbol_present', 'symbol_name')
logging.debug('Found trace line: %s' % line.strip())
if frame <= last_frame and (trace_lines or value_lines):
java_lines = []
if pid != -1 and pid in java_stderr_by_pid:
java_lines = java_stderr_by_pid[pid]
PrintOutput(trace_lines, value_lines, java_lines, more_info)
PrintDivider()
trace_lines = []
value_lines = []
pid = -1
last_frame = frame
if area == UNKNOWN or area == HEAP or area == STACK:
trace_lines.append((code_addr, '', area))
else:
logging.debug('Identified lib: %s' % area)
# If a calls b which further calls c and c is inlined to b, we want to
# display "a -> b -> c" in the stack trace instead of just "a -> c"
# To use llvm symbolizer, the hexadecimal address has to start with 0x.
info = llvm_symbolizer.GetSymbolInformation(
os.path.join(symbol.SYMBOLS_DIR, symbol.TranslateLibPath(area)),
'0x' + code_addr)
logging.debug('symbol information: %s' % info)
nest_count = len(info) - 1
for source_symbol, source_location in info:
if nest_count > 0:
nest_count = nest_count - 1
trace_lines.append(('v------>', source_symbol, source_location))
else:
trace_lines.append((code_addr,
source_symbol,
source_location))
match = _VALUE_LINE.match(line)
if match:
(unused_, addr, value, area, symbol_present, symbol_name) = match.groups()
if area == UNKNOWN or area == HEAP or area == STACK or not area:
value_lines.append((addr, value, '', area))
else:
info = llvm_symbolizer.GetSymbolInformation(
os.path.join(symbol.SYMBOLS_DIR, symbol.TranslateLibPath(area)),
'0x' + value)
source_symbol, source_location = info.pop()
value_lines.append((addr,
value,
source_symbol,
source_location))
java_lines = []
if pid != -1 and pid in java_stderr_by_pid:
java_lines = java_stderr_by_pid[pid]
PrintOutput(trace_lines, value_lines, java_lines, more_info)
def UpdateLibrarySearchPath(so_dirs):
# All dirs in so_dirs must be same, since a dir represents the cpu arch.
so_dir = set(so_dirs)
so_dir_len = len(so_dir)
if so_dir_len > 0:
if so_dir_len > 1:
raise Exception("Found different so dirs, they are %s", repr(so_dir))
else:
search_path = so_dir.pop()
print "Search libraries in " + search_path
symbol.SetSecondaryAbiOutputPath(search_path)
def GetUncompressedSharedLibraryFromAPK(apkname, offset):
"""Check if there is uncompressed shared library at specifc offset of APK."""
FILE_NAME_LEN_OFFSET = 26
FILE_NAME_OFFSET = 30
soname = ""
sosize = 0
with zipfile.ZipFile(apkname, 'r') as apk:
for infoList in apk.infolist():
filename, file_extension = os.path.splitext(infoList.filename)
if (file_extension == '.so' and
infoList.file_size == infoList.compress_size):
with open(apkname, 'rb') as f:
f.seek(infoList.header_offset + FILE_NAME_LEN_OFFSET)
file_name_len = struct.unpack('H', f.read(2))[0]
extra_field_len = struct.unpack('H', f.read(2))[0]
file_offset = (infoList.header_offset + FILE_NAME_OFFSET +
file_name_len + extra_field_len)
f.seek(file_offset)
if offset == file_offset and f.read(4) == "\x7fELF":
soname = infoList.filename
sosize = infoList.file_size
break
return soname, sosize
def _GetSharedLibraryInHost(soname, dirs):
"""Find a shared library by name in a list of directories.
Args:
soname: library name (e.g. libfoo.so)
dirs: list of directories to look for the corresponding file.
Returns:
host library path if found, or None
"""
for dir in dirs:
host_so_file = os.path.join(dir, os.path.basename(soname))
if not os.path.isfile(host_so_file):
continue
logging.debug("%s match to the one in APK" % host_so_file)
return host_so_file
def _FindSharedLibraryFromAPKs(out_dir, offset):
"""Find the shared library at the specifc offset of an APK file.
WARNING: This function will look at *all* the apks under $out_dir/apks/
looking for native libraries they may contain at |offset|.
This is error-prone, since a typical full Chrome build has more than a
hundred APKs these days, meaning that several APKs might actually match
the offset.
The function tries to detect this by looking at the names of the
extracted libraries. If they are all the same, it will consider that
as a success, and return its name, even if the APKs embed the same
library at different offsets!!
If there are more than one library at offset from the pool of all APKs,
the function prints an error message and fails.
TODO(digit): Either find a way to pass a list of valid APKs here, or
rewrite this script entirely to avoid so many other problematic things
in it.
Args:
out_dir: Chromium output directory.
offset: APK file offset, as extracted from the stack trace.
Returns:
A (library_name, host_library_path) tuple on success, or (None, None)
in case of failure.
"""
apk_dir = os.path.join(out_dir, "apks")
if not os.path.isdir(apk_dir):
return (None, None)
apks = [os.path.join(apk_dir, f) for f in os.listdir(apk_dir)
if (os.path.isfile(os.path.join(apk_dir, f)) and
os.path.splitext(f)[1] == '.apk')]
shared_libraries = []
for apk in apks:
soname, sosize = GetUncompressedSharedLibraryFromAPK(apk, offset)
if soname == "":
continue
# The relocation section of libraries in APK is packed, we can't
# detect library by its size, and have to rely on the order of lib
# directories; for a specific ARCH, the libraries are in either
# out_dir or out_dir/android_ARCH, and android_ARCH directory could
# exists or not, so having android_ARCH directory be in first, we
# will find the correct lib.
dirs = [
os.path.join(out_dir, "android_%s" % symbol.ARCH),
out_dir,
]
host_so_file = _GetSharedLibraryInHost(soname, dirs)
if host_so_file:
shared_libraries += [(soname, host_so_file)]
# If there are more than one libraries found, it means detecting
# library failed.
number_of_library = len(shared_libraries)
if number_of_library == 1:
return shared_libraries[0]
elif number_of_library > 1:
print "More than one libraries could be loaded from APK."
return (None, None)
def _FindAbi(lines):
for line in lines:
match = _ABI_LINE.search(line)
if match:
return match.group('abi')

View File

@ -0,0 +1,133 @@
#!/usr/bin/env python
#
# Copyright (c) 2015 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.
"""Identifies address adjustments required for native crash dumps."""
import glob
import os.path
import re
import subprocess
_BASE_APK = 'base.apk'
_LIBCHROME_SO = 'libchrome.so'
_BUILD_FINGERPRINT_RE = re.compile('.*Build fingerprint: (.*)$')
def GetTargetAndroidVersionNumber(lines):
"""Return the Android major version number from the build fingerprint.
Args:
lines: Lines read from the tombstone file, before preprocessing.
Returns:
5, 6, etc, or None if not determinable (developer build?)
"""
# For example, "Build fingerprint: 'Android/aosp_flo/flo:5.1.1/...'" is 5.
for line in lines:
m = _BUILD_FINGERPRINT_RE.match(line)
if not m:
continue
fingerprint = m.group(1)
try:
version = fingerprint.split('/')[2].split(':')[1].split('.')[0]
return int(version)
except Exception:
pass
return None
def _HasElfHeader(path):
"""Return True if the file at the given path has an ELF magic header.
Minimal check only, for 'ELF' in bytes 1 to 3 of the file. Filters out
the zero-byte false-positives such as libchromeview.so returned by glob.
Args:
path: Path to file to check.
Returns:
True or False
"""
with open(path) as stream:
elf_header = stream.read(4)
return len(elf_header) == 4 and elf_header[1:4] == 'ELF'
def _ReadElfProgramHeaders(lib):
"""Return an iterable of program headers, from 'readelf -l ...'.
Uses the platform readelf in all cases. This is somewhat lazy, but suffices
in practice because program headers in ELF files are architecture-agnostic.
Args:
lib: Library file to read.
Returns:
[readelf -l output line, ...]
"""
string = subprocess.check_output(['readelf', '-l', lib])
return string.split('\n')
def _FindMinLoadVaddr(lib):
"""Return the minimum VirtAddr field of all library LOAD segments.
Args:
lib: Library file to read.
Returns:
Min VirtAddr field for all LOAD segments, or 0 if none found.
"""
vaddrs = []
# Locate LOAD lines and find the smallest VirtAddr field, eg:
# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# LOAD 0x000000 0x001d6000 0x001d6000 0x20f63fc 0x20f63fc R E 0x1000
# LOAD 0x20f6970 0x022cd970 0x022cd970 0x182df8 0x1b4490 RW 0x1000
# would return 0x1d6000. Ignores all non-LOAD lines.
for line in _ReadElfProgramHeaders(lib):
elements = line.split()
if elements and elements[0] == 'LOAD':
vaddrs.append(int(elements[2], 16))
if vaddrs:
return min(vaddrs)
return 0
def GetLoadVaddrs(stripped_libs=None, stripped_libs_dir=None):
"""Return a dict of minimum VirtAddr for libraries in the given directory.
The dictionary returned may be passed to stack_core.ConvertTrace(). In
pre-M Android releases the addresses printed by debuggerd into tombstones
do not take account of non-zero vaddrs. Here we collect this information,
so that we can use it later to correct such debuggerd tombstones.
Args:
stripped_libs_dir: Path to directory containing apk's stripped libraries.
Returns:
{'libchrome.so': 12345, ...}
"""
if not stripped_libs:
stripped_libs = []
if stripped_libs_dir:
stripped_libs.extend(glob.glob(os.path.join(stripped_libs_dir, '*.so')))
libs = [l for l in stripped_libs if _HasElfHeader(l)]
load_vaddrs = {}
for lib in libs:
min_vaddr = _FindMinLoadVaddr(lib)
if min_vaddr:
# Store with the library basename as the key. This is because once on
# the device its path may not fully match its place in the APK staging
# directory
load_vaddrs[os.path.basename(lib)] = min_vaddr
# Direct load from APK causes debuggerd to tag trace lines as if from the
# file .../base.apk. So if we encounter a libchrome.so with packed
# relocations, replicate this as base.apk so that later adjustment code
# finds the appropriate adjustment.
if _LIBCHROME_SO in load_vaddrs:
load_vaddrs[_BASE_APK] = load_vaddrs[_LIBCHROME_SO]
return load_vaddrs

View File

@ -0,0 +1,498 @@
#!/usr/bin/python
#
# Copyright (C) 2013 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.
"""Module for looking up symbolic debugging information.
The information can include symbol names, offsets, and source locations.
"""
import glob
import itertools
import logging
import os
import re
import struct
import subprocess
import sys
import zipfile
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, os.pardir, os.pardir,
'build', 'android'))
from pylib import constants
from pylib.constants import host_paths
from pylib.symbols import elf_symbolizer
# WARNING: These global variables can be modified by other scripts!
SYMBOLS_DIR = constants.DIR_SOURCE_ROOT
CHROME_SYMBOLS_DIR = None
ARCH = "arm"
_SECONDARY_ABI_OUTPUT_PATH = None
# See:
# http://bugs.python.org/issue14315
# https://hg.python.org/cpython/rev/6dd5e9556a60#l2.8
def _PatchZipFile():
oldDecodeExtra = zipfile.ZipInfo._decodeExtra
def decodeExtra(self):
try:
oldDecodeExtra(self)
except struct.error:
pass
zipfile.ZipInfo._decodeExtra = decodeExtra
_PatchZipFile()
# Used by _GetApkPackageName() to extract package name from aapt dump output.
_PACKAGE_NAME_RE = re.compile(r'package: .*name=\'(\S*)\'')
# Used to speed up _GetApkPackageName() because the latter is called far too
# often at the moment. Maps APK file paths to the corresponding package name.
_package_name_cache = {}
def _GetApkPackageName(apk_path):
"""Return the package name of a given apk."""
package_name = _package_name_cache.get(apk_path, None)
if package_name:
return package_name
aapt_path = host_paths.GetAaptPath()
aapt_output = subprocess.check_output(
[aapt_path, 'dump', 'badging', apk_path]).split('\n')
for line in aapt_output:
match = _PACKAGE_NAME_RE.match(line)
if match:
package_name = match.group(1)
_package_name_cache[apk_path] = package_name
logging.debug('Package name %s for %s', package_name, apk_path)
return package_name
return None
def _PathListJoin(prefix_list, suffix_list):
"""Returns each prefix in prefix_list joined with each suffix in suffix list.
Args:
prefix_list: list of path prefixes.
suffix_list: list of path suffixes.
Returns:
List of paths each of which joins a prefix with a suffix.
"""
return [
os.path.join(prefix, suffix)
for suffix in suffix_list for prefix in prefix_list ]
def GetCandidates(dirs, filepart, candidate_fun):
"""Returns a list of candidate filenames, sorted by modification time.
Args:
dirs: a list of the directory part of the pathname.
filepart: the file part of the pathname.
candidate_fun: a function to apply to each candidate, returns a list.
Returns:
A list of candidate files ordered by modification time, newest first.
"""
candidates = _PathListJoin(dirs, [filepart])
logging.debug('GetCandidates: prefiltered candidates = %s' % candidates)
candidates = list(
itertools.chain.from_iterable(map(candidate_fun, candidates)))
candidates.sort(key=os.path.getmtime, reverse=True)
return candidates
# Used by _GetCandidateApks() to speed up its result.
_cached_candidate_apks = None
def _GetCandidateApks():
"""Returns a list of APKs which could contain the library.
Args:
None
Returns:
list of APK file paths which could contain the library.
"""
global _cached_candidate_apks
if _cached_candidate_apks is not None:
return _cached_candidate_apks
apk_dir = os.path.join(constants.GetOutDirectory(), 'apks')
candidates = GetCandidates([apk_dir], '*.apk', glob.glob)
_cached_candidate_apks = candidates
return candidates
def GetCrazyLib(apk_filename):
"""Returns the name of the first crazy library from this APK.
Args:
apk_filename: name of an APK file.
Returns:
Name of the first library which would be crazy loaded from this APK.
"""
zip_file = zipfile.ZipFile(apk_filename, 'r')
for filename in zip_file.namelist():
match = re.match('lib/[^/]*/crazy.(lib.*[.]so)', filename)
if match:
return match.group(1)
def GetApkFromLibrary(device_library_path):
match = re.match(r'.*/([^/]*)-[0-9]+(\/[^/]*)?\.apk$', device_library_path)
if not match:
return None
return match.group(1)
def GetMatchingApks(package_name):
"""Find any APKs which match the package indicated by the device_apk_name.
Args:
package_name: package name of the APK on the device.
Returns:
A list of APK filenames which could contain the desired library.
"""
return [apk_path for apk_path in _GetCandidateApks() if (
_GetApkPackageName(apk_path) == package_name)]
def MapDeviceApkToLibrary(device_apk_name):
"""Provide a library name which corresponds with device_apk_name.
Args:
device_apk_name: name of the APK on the device.
Returns:
Name of the library which corresponds to that APK.
"""
matching_apks = GetMatchingApks(device_apk_name)
logging.debug('MapDeviceApkToLibrary: matching_apks=%s' % matching_apks)
for matching_apk in matching_apks:
crazy_lib = GetCrazyLib(matching_apk)
if crazy_lib:
return crazy_lib
def GetLibrarySearchPaths():
"""Return a list of directories where to find native shared libraries."""
if _SECONDARY_ABI_OUTPUT_PATH:
return _PathListJoin([_SECONDARY_ABI_OUTPUT_PATH], ['lib.unstripped', '.'])
if CHROME_SYMBOLS_DIR:
return [CHROME_SYMBOLS_DIR]
output_dir = constants.GetOutDirectory()
# GN places stripped libraries under $CHROMIUM_OUTPUT_DIR and unstripped ones
# under $CHROMIUM_OUTPUT_OUT/lib.unstripped. Place the unstripped path before
# to get symbols from them when they exist.
return _PathListJoin([output_dir], ['lib.unstripped', '.'])
def GetCandidateLibraries(library_name):
"""Returns a list of candidate library filenames.
Args:
library_name: basename of the library to match.
Returns:
A list of matching library filenames for library_name.
"""
def extant_library(filename):
if (os.path.exists(filename)
and elf_symbolizer.ContainsElfMagic(filename)):
return [filename]
return []
candidates = GetCandidates(
GetLibrarySearchPaths(), library_name,
extant_library)
# For GN, candidates includes both stripped an unstripped libraries. Stripped
# libraries are always newer. Explicitly look for .unstripped and sort them
# ahead.
candidates.sort(key=lambda c: int('unstripped' not in c))
return candidates
def TranslateLibPath(lib):
# The filename in the stack trace maybe an APK name rather than a library
# name. This happens when the library was loaded directly from inside the
# APK. If this is the case we try to figure out the library name by looking
# for a matching APK file and finding the name of the library in contains.
# The name of the APK file on the device is of the form
# <package_name>-<number>.apk. The APK file on the host may have any name
# so we look at the APK badging to see if the package name matches.
apk = GetApkFromLibrary(lib)
if apk is not None:
logging.debug('TranslateLibPath: apk=%s' % apk)
mapping = MapDeviceApkToLibrary(apk)
if mapping:
lib = mapping
# SymbolInformation(lib, addr) receives lib as the path from symbols
# root to the symbols file. This needs to be translated to point to the
# correct .so path. If the user doesn't explicitly specify which directory to
# use, then use the most recently updated one in one of the known directories.
# If the .so is not found somewhere in CHROME_SYMBOLS_DIR, leave it
# untranslated in case it is an Android symbol in SYMBOLS_DIR.
library_name = os.path.basename(lib)
logging.debug('TranslateLibPath: lib=%s library_name=%s' % (lib, library_name))
candidate_libraries = GetCandidateLibraries(library_name)
logging.debug('TranslateLibPath: candidate_libraries=%s' % candidate_libraries)
if not candidate_libraries:
return lib
library_path = os.path.relpath(candidate_libraries[0], SYMBOLS_DIR)
logging.debug('TranslateLibPath: library_path=%s' % library_path)
return library_path
def _FormatSymbolWithOffset(symbol, offset):
if offset == 0:
return symbol
return "%s+%d" % (symbol, offset)
def SetSecondaryAbiOutputPath(path):
global _SECONDARY_ABI_OUTPUT_PATH
if _SECONDARY_ABI_OUTPUT_PATH and _SECONDARY_ABI_OUTPUT_PATH != path:
raise Exception ('SetSecondaryAbiOutputPath() was already called with a ' +
'different value, previous: %s new: %s' % (
_SECONDARY_ABI_OUTPUT_PATH, path))
else:
_SECONDARY_ABI_OUTPUT_PATH = path
def SymbolInformationForSet(lib, unique_addrs, get_detailed_info,
cpu_arch=ARCH):
"""Look up symbol information for a set of addresses from the given library.
Args:
lib: library (or executable) pathname containing symbols
unique_addrs: set of hexidecimal addresses
get_detailed_info: If True, add additional info from objdump.
cpu_arch: Target CPU architecture.
Returns:
A dictionary of the form {addr: [(source_symbol, source_location,
object_symbol_with_offset)]} where each address has a list of
associated symbols and locations. The list is always non-empty.
If the function has been inlined then the list may contain
more than one element with the symbols for the most deeply
nested inlined location appearing first. The list is
always non-empty, even if no information is available.
Usually you want to display the source_location and
object_symbol_with_offset from the last element in the list.
"""
if not lib:
return None
addr_to_line = _CallAddr2LineForSet(lib, unique_addrs, cpu_arch)
if not addr_to_line:
return None
if get_detailed_info:
addr_to_objdump = _CallObjdumpForSet(lib, unique_addrs, cpu_arch)
if not addr_to_objdump:
return None
else:
addr_to_objdump = dict((addr, ("", 0)) for addr in unique_addrs)
result = {}
for addr in unique_addrs:
source_info = addr_to_line.get(addr)
if not source_info:
source_info = [(None, None)]
if addr in addr_to_objdump:
(object_symbol, object_offset) = addr_to_objdump.get(addr)
object_symbol_with_offset = _FormatSymbolWithOffset(object_symbol,
object_offset)
else:
object_symbol_with_offset = None
result[addr] = [(source_symbol, source_location, object_symbol_with_offset)
for (source_symbol, source_location) in source_info]
return result
class _MemoizedForSet(object):
"""Decorator class used to memoize CallXXXForSet() results."""
def __init__(self, fn):
self.fn = fn
self.cache = {}
self.cpu_arch = None
def __call__(self, lib, unique_addrs, cpu_arch):
if self.cpu_arch is None:
self.cpu_arch = cpu_arch
else:
# Sanity check, this doesn't expect cpu_arch to change.
assert self.cpu_arch == cpu_arch
lib_cache = self.cache.setdefault(lib, {})
uncached_addrs = [k for k in unique_addrs if k not in lib_cache]
if uncached_addrs:
lib_cache.update((k, None) for k in uncached_addrs)
result = self.fn(lib, uncached_addrs, cpu_arch)
if result:
lib_cache.update(result)
return dict((k, lib_cache[k]) for k in unique_addrs if lib_cache[k])
@_MemoizedForSet
def _CallAddr2LineForSet(lib, unique_addrs, cpu_arch):
"""Look up line and symbol information for a set of addresses.
Args:
lib: library (or executable) pathname containing symbols
unique_addrs: set of string hexidecimal addresses look up.
cpu_arch: Target CPU architecture.
Returns:
A dictionary of the form {addr: [(symbol, file:line)]} where
each address has a list of associated symbols and locations
or an empty list if no symbol information was found.
If the function has been inlined then the list may contain
more than one element with the symbols for the most deeply
nested inlined location appearing first.
"""
if not lib:
return None
symbols = SYMBOLS_DIR + lib
if not os.path.splitext(symbols)[1] in ['', '.so', '.apk']:
return None
if not os.path.isfile(symbols):
return None
addrs = sorted(unique_addrs)
result = {}
def _Callback(sym, addr):
records = []
while sym: # Traverse all the inlines following the |inlined_by| chain.
if sym.source_path and sym.source_line:
location = '%s:%d' % (sym.source_path, sym.source_line)
else:
location = None
records += [(sym.name, location)]
sym = sym.inlined_by
result[addr] = records
symbolizer = elf_symbolizer.ELFSymbolizer(
elf_file_path=symbols,
addr2line_path=host_paths.ToolPath("addr2line", cpu_arch),
callback=_Callback,
inlines=True)
for addr in addrs:
symbolizer.SymbolizeAsync(int(addr, 16), addr)
symbolizer.Join()
return result
@_MemoizedForSet
def _CallObjdumpForSet(lib, unique_addrs, cpu_arch):
"""Use objdump to find out the names of the containing functions.
Args:
lib: library (or executable) pathname containing symbols
unique_addrs: set of string hexidecimal addresses to find the functions for.
cpu_arch: Target CPU architecture.
Returns:
A dictionary of the form {addr: (string symbol, offset)}.
"""
if not lib:
return None
symbols = SYMBOLS_DIR + lib
if not os.path.exists(symbols):
return None
symbols = SYMBOLS_DIR + lib
if not os.path.exists(symbols):
return None
result = {}
# Function lines look like:
# 000177b0 <android::IBinder::~IBinder()+0x2c>:
# We pull out the address and function first. Then we check for an optional
# offset. This is tricky due to functions that look like "operator+(..)+0x2c"
func_regexp = re.compile("(^[a-f0-9]*) \<(.*)\>:$")
offset_regexp = re.compile("(.*)\+0x([a-f0-9]*)")
# A disassembly line looks like:
# 177b2: b510 push {r4, lr}
asm_regexp = re.compile("(^[ a-f0-9]*):[ a-f0-0]*.*$")
for target_addr in unique_addrs:
start_addr_dec = str(StripPC(int(target_addr, 16)))
stop_addr_dec = str(StripPC(int(target_addr, 16)) + 8)
cmd = [host_paths.ToolPath("objdump", cpu_arch),
"--section=.text",
"--demangle",
"--disassemble",
"--start-address=" + start_addr_dec,
"--stop-address=" + stop_addr_dec,
symbols]
current_symbol = None # The current function symbol in the disassembly.
current_symbol_addr = 0 # The address of the current function.
stream = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
for line in stream:
# Is it a function line like:
# 000177b0 <android::IBinder::~IBinder()>:
components = func_regexp.match(line)
if components:
# This is a new function, so record the current function and its address.
current_symbol_addr = int(components.group(1), 16)
current_symbol = components.group(2)
# Does it have an optional offset like: "foo(..)+0x2c"?
components = offset_regexp.match(current_symbol)
if components:
current_symbol = components.group(1)
offset = components.group(2)
if offset:
current_symbol_addr -= int(offset, 16)
# Is it an disassembly line like:
# 177b2: b510 push {r4, lr}
components = asm_regexp.match(line)
if components:
addr = components.group(1)
i_addr = int(addr, 16)
i_target = StripPC(int(target_addr, 16))
if i_addr == i_target:
result[target_addr] = (current_symbol, i_target - current_symbol_addr)
stream.close()
return result

View File

@ -0,0 +1,24 @@
# Copyright 2016 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.
import("//build/config/android/rules.gni")
android_java_prebuilt("runner_java") {
testonly = true
jar_path = "lib/runner-release-no-dep.jar"
deps = [
":exposed_instrumentation_api_publish_java",
"//third_party/guava:guava_android_java",
"//third_party/junit",
]
}
android_java_prebuilt("exposed_instrumentation_api_publish_java") {
jar_path = "lib/exposed-instrumentation-api-publish-no-dep.jar"
}
android_aar_prebuilt("rules_java") {
testonly = true
aar_path = "lib/rules.aar"
}

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,3 @@
jbudorick@chromium.org
mikecase@chromium.org
yolandyan@chromium.org

View File

@ -0,0 +1,14 @@
Name: Android Testing Support Library Test Runner
Short Name: runner
URL: https://github.com/googlesamples/android-testing/tree/master/ui/espresso/BasicSampleBundled
Version: 0.5
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: no
Description:
These static jars are part of Android Testing Support Library. They are needed
for Android JUnit runner. IMPORTANT: There should only be one version of
espresso library (crbug.com/622057)
Local Modifications: None

View File

@ -0,0 +1,12 @@
# Copyright 2017 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.
# To create CIPD package run the following command.
# cipd create --pkg-def cipd.yaml -tag version:$(cat version.txt)
package: chromium/third_party/android_support_test_runner
description: android_support_test_runner Java libraries
data:
- file: lib/exposed-instrumentation-api-publish-no-dep.jar
- file: lib/rules.aar
- file: lib/runner-release-no-dep.jar

View File

@ -0,0 +1,13 @@
# Generated by //build/android/gyp/aar.py
# To regenerate, use "update_android_aar_prebuilts = true" and run "gn gen".
aidl = [ ]
assets = [ ]
has_classes_jar = true
has_native_libraries = false
has_proguard_flags = false
has_r_text_file = true
is_manifest_empty = true
resources = [ "res/values/values.xml" ]
subjar_tuples = [ ]
subjars = [ ]

350
third_party/android_system_sdk/LICENSE vendored Normal file
View File

@ -0,0 +1,350 @@
GNU General Public License, version 2,
with the Classpath Exception
The GNU General Public License (GPL)
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your freedom to share
and change it. By contrast, the GNU General Public License is intended to
guarantee your freedom to share and change free software--to make sure the
software is free for all its users. This General Public License applies to
most of the Free Software Foundation's software and to any other program whose
authors commit to using it. (Some other Free Software Foundation software is
covered by the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not price. Our
General Public Licenses are designed to make sure that you have the freedom to
distribute copies of free software (and charge for this service if you wish),
that you receive source code or can get it if you want it, that you can change
the software or use pieces of it in new free programs; and that you know you
can do these things.
To protect your rights, we need to make restrictions that forbid anyone to deny
you these rights or to ask you to surrender the rights. These restrictions
translate to certain responsibilities for you if you distribute copies of the
software, or if you modify it.
For example, if you distribute copies of such a program, whether gratis or for
a fee, you must give the recipients all the rights that you have. You must
make sure that they, too, receive or can get the source code. And you must
show them these terms so they know their rights.
We protect your rights with two steps: (1) copyright the software, and (2)
offer you this license which gives you legal permission to copy, distribute
and/or modify the software.
Also, for each author's protection and ours, we want to make certain that
everyone understands that there is no warranty for this free software. If the
software is modified by someone else and passed on, we want its recipients to
know that what they have is not the original, so that any problems introduced
by others will not reflect on the original authors' reputations.
Finally, any free program is threatened constantly by software patents. We
wish to avoid the danger that redistributors of a free program will
individually obtain patent licenses, in effect making the program proprietary.
To prevent this, we have made it clear that any patent must be licensed for
everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification
follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains a notice
placed by the copyright holder saying it may be distributed under the terms of
this General Public License. The "Program", below, refers to any such program
or work, and a "work based on the Program" means either the Program or any
derivative work under copyright law: that is to say, a work containing the
Program or a portion of it, either verbatim or with modifications and/or
translated into another language. (Hereinafter, translation is included
without limitation in the term "modification".) Each licensee is addressed as
"you".
Activities other than copying, distribution and modification are not covered by
this License; they are outside its scope. The act of running the Program is
not restricted, and the output from the Program is covered only if its contents
constitute a work based on the Program (independent of having been made by
running the Program). Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's source code as
you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this License
and to the absence of any warranty; and give any other recipients of the
Program a copy of this License along with the Program.
You may charge a fee for the physical act of transferring a copy, and you may
at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion of it, thus
forming a work based on the Program, and copy and distribute such modifications
or work under the terms of Section 1 above, provided that you also meet all of
these conditions:
a) You must cause the modified files to carry prominent notices stating
that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or
in part contains or is derived from the Program or any part thereof, to be
licensed as a whole at no charge to all third parties under the terms of
this License.
c) If the modified program normally reads commands interactively when run,
you must cause it, when started running for such interactive use in the
most ordinary way, to print or display an announcement including an
appropriate copyright notice and a notice that there is no warranty (or
else, saying that you provide a warranty) and that users may redistribute
the program under these conditions, and telling the user how to view a copy
of this License. (Exception: if the Program itself is interactive but does
not normally print such an announcement, your work based on the Program is
not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable
sections of that work are not derived from the Program, and can be reasonably
considered independent and separate works in themselves, then this License, and
its terms, do not apply to those sections when you distribute them as separate
works. But when you distribute the same sections as part of a whole which is a
work based on the Program, the distribution of the whole must be on the terms
of this License, whose permissions for other licensees extend to the entire
whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your
rights to work written entirely by you; rather, the intent is to exercise the
right to control the distribution of derivative or collective works based on
the Program.
In addition, mere aggregation of another work not based on the Program with the
Program (or with a work based on the Program) on a volume of a storage or
distribution medium does not bring the other work under the scope of this
License.
3. You may copy and distribute the Program (or a work based on it, under
Section 2) in object code or executable form under the terms of Sections 1 and
2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable source
code, which must be distributed under the terms of Sections 1 and 2 above
on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to
give any third party, for a charge no more than your cost of physically
performing source distribution, a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of Sections 1
and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to
distribute corresponding source code. (This alternative is allowed only
for noncommercial distribution and only if you received the program in
object code or executable form with such an offer, in accord with
Subsection b above.)
The source code for a work means the preferred form of the work for making
modifications to it. For an executable work, complete source code means all
the source code for all modules it contains, plus any associated interface
definition files, plus the scripts used to control compilation and installation
of the executable. However, as a special exception, the source code
distributed need not include anything that is normally distributed (in either
source or binary form) with the major components (compiler, kernel, and so on)
of the operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the source
code from the same place counts as distribution of the source code, even though
third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as
expressly provided under this License. Any attempt otherwise to copy, modify,
sublicense or distribute the Program is void, and will automatically terminate
your rights under this License. However, parties who have received copies, or
rights, from you under this License will not have their licenses terminated so
long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it.
However, nothing else grants you permission to modify or distribute the Program
or its derivative works. These actions are prohibited by law if you do not
accept this License. Therefore, by modifying or distributing the Program (or
any work based on the Program), you indicate your acceptance of this License to
do so, and all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the Program),
the recipient automatically receives a license from the original licensor to
copy, distribute or modify the Program subject to these terms and conditions.
You may not impose any further restrictions on the recipients' exercise of the
rights granted herein. You are not responsible for enforcing compliance by
third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues), conditions
are imposed on you (whether by court order, agreement or otherwise) that
contradict the conditions of this License, they do not excuse you from the
conditions of this License. If you cannot distribute so as to satisfy
simultaneously your obligations under this License and any other pertinent
obligations, then as a consequence you may not distribute the Program at all.
For example, if a patent license would not permit royalty-free redistribution
of the Program by all those who receive copies directly or indirectly through
you, then the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply and
the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or
other property right claims or to contest validity of any such claims; this
section has the sole purpose of protecting the integrity of the free software
distribution system, which is implemented by public license practices. Many
people have made generous contributions to the wide range of software
distributed through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing to
distribute software through any other system and a licensee cannot impose that
choice.
This section is intended to make thoroughly clear what is believed to be a
consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain
countries either by patents or by copyrighted interfaces, the original
copyright holder who places the Program under this License may add an explicit
geographical distribution limitation excluding those countries, so that
distribution is permitted only in or among countries not thus excluded. In
such case, this License incorporates the limitation as if written in the body
of this License.
9. The Free Software Foundation may publish revised and/or new versions of the
General Public License from time to time. Such new versions will be similar in
spirit to the present version, but may differ in detail to address new problems
or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any later
version", you have the option of following the terms and conditions either of
that version or of any later version published by the Free Software Foundation.
If the Program does not specify a version number of this License, you may
choose any version ever published by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free programs
whose distribution conditions are different, write to the author to ask for
permission. For software which is copyrighted by the Free Software Foundation,
write to the Free Software Foundation; we sometimes make exceptions for this.
Our decision will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE
PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE
PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA
BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER
OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest possible
use to the public, the best way to achieve this is to make it free software
which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach
them to the start of each source file to most effectively convey the exclusion
of warranty; and each file should have at least the "copyright" line and a
pointer to where the full notice is found.
One line to give the program's name and a brief idea of what it does.
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this when it
starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
software, and you are welcome to redistribute it under certain conditions;
type 'show c' for details.
The hypothetical commands 'show w' and 'show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may be
called something other than 'show w' and 'show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your school,
if any, to sign a "copyright disclaimer" for the program, if necessary. Here
is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
'Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General Public
License instead of this License.
"CLASSPATH" EXCEPTION TO THE GPL
Certain source files distributed by Oracle America and/or its affiliates are
subject to the following clarification and special exception to the GPL, but
only where Oracle has expressly included in the particular source file's header
the words "Oracle designates this particular file as subject to the "Classpath"
exception as provided by Oracle in the LICENSE file that accompanied this code."
Linking this library statically or dynamically with other modules is making
a combined work based on this library. Thus, the terms and conditions of
the GNU General Public License cover the whole combination.
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,
and to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent module,
the terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library. If
you modify this library, you may extend this exception to your version of
the library, but you are not obligated to do so. If you do not wish to do
so, delete this exception statement from your version.

5
third_party/android_system_sdk/OWNERS vendored Normal file
View File

@ -0,0 +1,5 @@
torne@chromium.org
tobiasjs@chromium.org
# TEAM: android-webview-dev@chromium.org
# COMPONENT: Mobile>WebView

View File

@ -0,0 +1,14 @@
Name: Android System SDK
Short Name: Android System SDK
Version: 0
Revision: OPM1.171018.001
License: GPL v2
License File: LICENSE
Security Critical: No
Description:
System SDK stubs for compiling Android Webview and Monochrome targets.
Revision is the BUILD ID of the Android release build.
Local Modifications:
None

View File

@ -0,0 +1,11 @@
# Copyright 2017 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.
# To create CIPD package run the following command.
# cipd create --pkg-def cipd.yaml -tag version:$(cat version.txt)
package: chromium/third_party/android_system_sdk
description: System SDK stubs for compile WebView and Monochrome targets
data:
- file: android-stubs-src.jar
- file: android_system.jar

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,4 @@
agrieve@chromium.org
estevenson@chromium.org
# COMPONENT: Build

View File

@ -0,0 +1,16 @@
Name: APK patch size estimator
URL: https://github.com/googlesamples/apk-patch-size-estimator
Version: 0.2
Date: Dec 16, 2016
Revision: 823a9504f237e4bb236cadf8b804ed27498e54fd
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: No
Description:
Estimates the size of Google Play patches and the new gzipped APK. See README.md
for more details.
Local Modifications:
- Removed the following files: CONTRIBUTING.md, tests/, images/.
- Changed file-by-file-tools.jar path to be absolute instead of relative.

View File

@ -0,0 +1,77 @@
# APK patch size estimator
Estimates the size of Google Play patches and the new gzipped APK.
From two APKs it estimates the size of the new patches as well as the size of the gzipped version of the new APK, which would be used in
cases where the patches are unexpectedly large, unavailable, or unsuitable.
Google Play uses multiple techniques to generate patches and generally picks the best match for the device. The best match is usually, but not always, the smallest patch file produced. The numbers that this script produces are **ESTIMATES** that can be used to characterize the impact of arbitrary changes to APKs. There is **NO GUARANTEE** that this tool produces the same patches or patch sizes that Google Play generates, stores or transmits, and the actual implementation within Google Play may change at any time, without notice.
***This is not an official Google product***
## Usage
The script uses *Python 2.7.X*, *bsdiff* and *Java* (you may need to install them in your system)
For the file-by-file estimation we use a jar (at /lib/file-by-file-tools.jar) generated from: https://github.com/andrewhayden/archive-patcher
#### To estimate the patches sizes of two APKs run:
```bash
$ python apk_patch_size_estimator.py --old-file old.apk --new-file new.apk
```
#### Output:
```bash
New APK size on disk: 18,271,850 bytes [17.4MB]
Estimated download size for new installs:
Full new APK (gzipped) size: 16,339,603 bytes [15.6MB]
Estimated download size for updates from the old APK, using Bsdiff:
Bsdiff patch (gzipped) size: 2,989,691 bytes [2.85MB]
Estimated download size for updates from the old APK,
using File-by-File:
File-by-File patch (gzipped) size: 1,912,751 bytes [1.82MB]
```
## Patches estimation process
### Bsdiff estimation
![](images/apk_patch_size_estimator.png)
### File-by-file estimation
Please visit https://github.com/andrewhayden/archive-patcher for further details.
## Installing external dependencies
The script uses *bsdiff*, *gzip*, *head*, *tail*, *bunzip2* and *java* binaries, [**bsdiff**](https://www.freebsd.org/cgi/man.cgi?query=bsdiff) is the only one not installed by defult in a unix based OS.
#### Linux debian-based
Install bsdiff:
```bash
sudo apt-get install bsdiff
```
#### OS X
Install bsdiff using [Homebrew](http://brew.sh/):
```bash
brew install bsdiff
```
#### Windows
The easiest way to run the script in Windows is by using [Cygwin](https://www.cygwin.com/), make sure you install *python* and *bsdiff* using Cygwin's installer/setup.
## Runing the unittests
#### Install unittest.mock
```bash
pip install mock
```
#### Run the test
```bash
python -m unittest discover tests/
```
## Authors
Julian Toledo
Andrew Hayden

View File

@ -0,0 +1,353 @@
#!/usr/bin/python
#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# 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.
"""Estimates the size of Google Play patches and the new gzipped APK.
From two APKs it estimates the size of new patches as well as
the size of a gzipped version of the APK, which would be used in
cases where patches are unexpectedly large, unavailable, or unsuitable.
Google Play uses multiple techniques to generate patches and generally picks
the best match for the device. The best match is usually, but not always, the
smallest patch file produced. The numbers that this script produces are
ESTIMATES that can be used to characterize the impact of arbitrary changes to
APKs. There is NO GUARANTEE that this tool produces the same patches or patch
sizes that Google Play generates, stores or transmits, and the actual
implementation within Google Play may change at any time, without notice.
"""
import sys
import argparse
import locale
import math
import os
import subprocess
_FILEBYFILE_JAR_PATH = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'lib', 'file-by-file-tools.jar'))
bsdiff_path = None
gzip_path = None
head_path = None
tail_path = None
bunzip2_path = None
java_path = None
def find_bins_or_die():
"""Checks that all the binaries needed are available.
The script needs bsdiff, gzip, head, tail and bunzip2
binaries availables in the system.
"""
global bsdiff_path
if not bsdiff_path:
bsdiff_path = find_binary('bsdiff')
global gzip_path
if not gzip_path:
gzip_path = find_binary('gzip')
global head_path
if not head_path:
head_path = find_binary('head')
global tail_path
if not tail_path:
tail_path = find_binary('tail')
global bunzip2_path
if not bunzip2_path:
bunzip2_path = find_binary('bunzip2')
global java_path
if not java_path:
java_path = find_binary('java')
def find_binary(binary_name):
"""Finds the path of a binary."""
try:
return subprocess.check_output(['which', binary_name]).strip()
except subprocess.CalledProcessError:
raise Exception(
'No "' + binary_name + '" on PATH, please install or fix PATH.')
def human_file_size(size):
"""Converts a byte size number into a human readable value."""
size = abs(size)
if size == 0:
return '0B'
units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
p = math.floor(math.log(size, 2) / 10)
return '%.3g%s' % (size/math.pow(1024, p), units[int(p)])
def calculate_bsdiff(old_file, new_file, save_patch_path, temp_path):
"""Estimates the size the Bsdiff patch gzipped.
Args:
old_file: the old APK file
new_file: the new APK file
save_patch_path: the path including filename to save the generated patch.
temp_path: the directory to use for the process
Returns:
a dictionary with:
'gzipped_new_file_size': the estimated size of the new gzipped APK
'bsdiff_patch_size': the estimated size of the patch from the two APKs
Raises:
Exception: if there is a problem calling the binaries needed in the process
"""
# Oddities:
# Bsdiff forces bzip2 compression, which starts after byte 32. Bzip2 isn't
# necessarily the best choice in all cases, and isn't necessarily what Google
# Play uses, so it has to be uncompressed and rewritten with gzip.
# Checks that the OS binaries needed are available
find_bins_or_die()
# Clean temp files
if os.path.exists(temp_path): os.remove(temp_path)
# Create the bsdiff of the two APKs
subprocess.check_output(
[bsdiff_path, old_file, new_file, temp_path])
# bsdiff paths
raw_bsdiff_path = temp_path + '.raw_bsdiff'
bzipped_bsdiff_path = raw_bsdiff_path + '.bz2'
gzipped_bsdiff_path = raw_bsdiff_path + '.gz'
bsdiff_header_path = temp_path + '.raw_bsdiff_header'
if os.path.exists(raw_bsdiff_path): os.remove(raw_bsdiff_path)
if os.path.exists(bzipped_bsdiff_path): os.remove(bzipped_bsdiff_path)
if os.path.exists(gzipped_bsdiff_path): os.remove(gzipped_bsdiff_path)
if os.path.exists(bsdiff_header_path): os.remove(bsdiff_header_path)
# Strip the first 32 bytes the bsdiff file, which is a bsdiff-specific header.
bsdiff_header = open(bsdiff_header_path, 'w')
p = subprocess.Popen(
[head_path, '-c', '32', bsdiff_header_path],
shell=False, stdout=bsdiff_header)
ret_code = p.wait()
if ret_code != 0:
raise Exception('Problem at the bsdiff step, returned code: %s' % ret_code)
bsdiff_header.flush()
bsdiff_header.close()
# Take the remainder of the file to gain an uncompressed copy.
bzipped_bsdiff_patch = open(bzipped_bsdiff_path, 'w')
p = subprocess.Popen(
[tail_path, '-c', '+33', temp_path],
shell=False, stdout=bzipped_bsdiff_patch)
ret_code = p.wait()
if ret_code != 0:
raise Exception('Problem at the tail step, returned code: %s' % ret_code)
bzipped_bsdiff_patch.flush()
bzipped_bsdiff_patch.close()
subprocess.check_output([bunzip2_path, '-d', '-q', bzipped_bsdiff_path])
# Prepend the 32 bytes of bsdiff header back onto the uncompressed file.
if save_patch_path:
rebuilt_bsdiff_path = save_patch_path + '-bsdiff-patch'
else:
rebuilt_bsdiff_path = raw_bsdiff_path + '.rebuilt'
gzipped_rebuilt_bsdiff_path = rebuilt_bsdiff_path + '.gz'
if os.path.exists(rebuilt_bsdiff_path): os.remove(rebuilt_bsdiff_path)
if os.path.exists(gzipped_rebuilt_bsdiff_path):
os.remove(gzipped_rebuilt_bsdiff_path)
rebuilt_bsdiff = open(rebuilt_bsdiff_path, 'w')
p = subprocess.Popen(
['cat', bsdiff_header_path, raw_bsdiff_path],
shell=False, stdout=rebuilt_bsdiff)
ret_code = p.wait()
if ret_code != 0:
raise Exception('Problem at the cat step, returned code: %s' % ret_code)
rebuilt_bsdiff.flush()
rebuilt_bsdiff.close()
# gzip the patch and get its size.
subprocess.check_output([gzip_path, '-9', rebuilt_bsdiff_path])
bsdiff_patch_size = os.stat(gzipped_rebuilt_bsdiff_path).st_size
# Clean up.
if os.path.exists(temp_path): os.remove(temp_path)
if os.path.exists(raw_bsdiff_path): os.remove(raw_bsdiff_path)
if os.path.exists(bsdiff_header_path): os.remove(bsdiff_header_path)
if os.path.exists(gzipped_bsdiff_path): os.remove(gzipped_bsdiff_path)
if not save_patch_path and os.path.exists(gzipped_rebuilt_bsdiff_path):
os.remove(gzipped_rebuilt_bsdiff_path)
return bsdiff_patch_size
def calculate_new_apk(new_file, temp_path):
"""Estimates the size the new APK gzipped.
Args:
new_file: the new APK file
temp_path: the directory to use for the process
Returns:
the size of the new APK gzipped
Raises:
Exception: if there is a problem calling the binaries needed in the process
"""
# Checks that the OS binaries needed are available
find_bins_or_die()
# Clean temp files
if os.path.exists(temp_path + '.gz'): os.remove(temp_path + '.gz')
# gzip new APK and get its size
gzipped_new_file = open(temp_path, 'w')
p = subprocess.Popen(
[gzip_path, '--keep', '-c', '-9', new_file],
shell=False, stdout=gzipped_new_file)
ret_code = p.wait()
if ret_code != 0: raise Exception(
'Problem gzipping the new APK, returned code: %s' % ret_code)
gzipped_new_file.flush()
gzipped_new_file.close()
gzipped_size = os.stat(temp_path).st_size
# Clean up
if os.path.exists(temp_path + '.gz'): os.remove(temp_path + '.gz')
return gzipped_size
def calculate_filebyfile(old_file, new_file, save_patch_path, temp_path):
"""Estimates the size the File-by-File patch gzipped.
Args:
old_file: the old APK file
new_file: the new APK file
save_patch_path: the path including filename to save the generated patch.
temp_path: the directory to use for the process
Returns:
the size the File-by-File patch gzipped
Raises:
Exception: if there is a problem calling the binaries needed in the process
"""
# Checks that the OS binaries needed are available
find_bins_or_die()
# Clean temp files
if os.path.exists(temp_path): os.remove(temp_path)
if save_patch_path:
filebyfile_patch_path = save_patch_path + '-file-by-file-patch'
else:
filebyfile_patch_path = temp_path + '.filebyfile'
gzipped_filebyfile_patch_path = filebyfile_patch_path + '.gz'
if os.path.exists(gzipped_filebyfile_patch_path):
os.remove(gzipped_filebyfile_patch_path)
# file by file patch
# We use a jar from https://github.com/andrewhayden/archive-patcher
if os.path.exists(filebyfile_patch_path): os.remove(filebyfile_patch_path)
p = subprocess.Popen(
[java_path, '-jar', _FILEBYFILE_JAR_PATH, '--generate', '--old', old_file,
'--new', new_file, '--patch', filebyfile_patch_path],
shell=False)
ret_code = p.wait()
if ret_code != 0: raise Exception(
'Problem creating file by file patch, returned code: %s' % ret_code)
# gzip file by file patch and get its size
subprocess.check_output([gzip_path, '-9', filebyfile_patch_path])
gzipped_filebyfile_patch_size = os.stat(gzipped_filebyfile_patch_path).st_size
# Clean temp files
if os.path.exists(temp_path): os.remove(temp_path)
if not save_patch_path and os.path.exists(gzipped_filebyfile_patch_path):
os.remove(gzipped_filebyfile_patch_path)
return gzipped_filebyfile_patch_size
def main():
locale.setlocale(locale.LC_ALL, '')
parser = argparse.ArgumentParser(
description='Estimate the sizes of APK patches for Google Play')
parser.add_argument(
'--old-file', default=None, required=True,
help='the path to the "old" file to generate patches from.')
parser.add_argument(
'--new-file', default=None, required=True,
help='the path to the "new" file to generate patches from.')
parser.add_argument(
'--save-patch', default=None,
help='the path prefix to save the generated patches.')
parser.add_argument(
'--temp-dir', default='/tmp',
help='the temp directory to use for patch generation; defaults to /tmp')
if not sys.argv[1:]:
parser.print_help()
parser.exit()
args = parser.parse_args()
if not os.path.isfile(args.old_file):
raise Exception('File does not exist: %s' % args.old_file)
if not os.path.isfile(args.new_file):
raise Exception('File does not exist: %s' % args.new_file)
if args.save_patch and not os.access(
os.path.dirname(os.path.abspath(args.save_patch)), os.W_OK):
raise Exception('The save patch path is not writable: %s' % args.save_patch)
if args.save_patch and os.path.isdir(args.save_patch):
raise Exception('Please include the filename in the path: %s'
% args.save_patch)
save_patch_path = args.save_patch
if not os.path.isdir(args.temp_dir):
raise Exception('Temp directory does not exist: %s' % args.temp_dir)
temp_path = args.temp_dir + '/patch.tmp'
new_file_size = os.stat(args.new_file).st_size
bsdiff_size = calculate_bsdiff(
args.old_file, args.new_file, save_patch_path, temp_path)
gzipped_size = calculate_new_apk(args.new_file, temp_path)
# Calculate the size of the File-by-File patch gzipped
gzipped_filebyfile_patch_size = calculate_filebyfile(
args.old_file, args.new_file, save_patch_path, temp_path)
print ('\nNew APK size on disk: %s bytes [%s]'
% (locale.format('%d', new_file_size, grouping=True),
human_file_size(new_file_size)))
print '\nEstimated download size for new installs:'
print (' Full new APK (gzipped) size:'
' %s bytes [%s]'
% (locale.format('%d', gzipped_size, grouping=True),
human_file_size(gzipped_size)))
print '\nEstimated download size for updates from the old APK, using Bsdiff:'
print (' Bsdiff patch (gzipped) size: %s bytes [%s]'
% (locale.format('%d', bsdiff_size, grouping=True),
human_file_size(bsdiff_size)))
print '\nEstimated download size for updates from the old APK,'
print ' using File-by-File:'
print (' File-by-File patch (gzipped) size: %s bytes [%s]\n'
% (locale.format('%d', gzipped_filebyfile_patch_size, grouping=True),
human_file_size(gzipped_filebyfile_patch_size)))
if __name__ == '__main__':
main()

View File

@ -0,0 +1,10 @@
# Copyright 2017 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.
# To create CIPD package run the following command.
# cipd create --pkg-def cipd.yaml -tag version:$(cat version.txt)
package: chromium/third_party/apk-patch-size-estimator
description: apk-patch-size-estimator Java library
data:
- file: lib/file-by-file-tools.jar

12
third_party/ashmem/BUILD.gn vendored Normal file
View File

@ -0,0 +1,12 @@
# Copyright 2014 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.
assert(is_android)
source_set("ashmem") {
sources = [
"ashmem-dev.c",
"ashmem.h",
]
}

202
third_party/ashmem/LICENSE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

1
third_party/ashmem/OWNERS vendored Normal file
View File

@ -0,0 +1 @@
digit@chromium.org

10
third_party/ashmem/README.chromium vendored Normal file
View File

@ -0,0 +1,10 @@
Name: Android
URL: http://source.android.com
Description: Android shared memory implementation. Only applies to OS_ANDROID.
Version: 7203eb2a8a29a7b721a48cd291700f38f3da1456
Security Critical: yes
License: Apache 2.0
Patches:
0001-Add-ashmem-get-prot-region.path:
Add ashmem_get_prot_region() declaration and implementation to return
the current protection mask of a given Ashmem region.

105
third_party/ashmem/ashmem-dev.c vendored Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2008 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.
*/
/*
* Implementation of the user-space ashmem API for devices, which have our
* ashmem-enabled kernel. See ashmem-sim.c for the "fake" tmp-based version,
* used by the simulator.
*/
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/ashmem.h>
#include "ashmem.h"
#define ASHMEM_DEVICE "/dev/ashmem"
/*
* ashmem_create_region - creates a new ashmem region and returns the file
* descriptor, or <0 on error
*
* `name' is an optional label to give the region (visible in /proc/pid/maps)
* `size' is the size of the region, in page-aligned bytes
*/
int ashmem_create_region(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
if (name) {
char buf[ASHMEM_NAME_LEN];
strlcpy(buf, name, sizeof(buf));
ret = ioctl(fd, ASHMEM_SET_NAME, buf);
if (ret < 0)
goto error;
}
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
goto error;
return fd;
error:
close(fd);
return ret;
}
int ashmem_set_prot_region(int fd, int prot)
{
return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
}
int ashmem_get_prot_region(int fd)
{
return ioctl(fd, ASHMEM_GET_PROT_MASK);
}
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
return ioctl(fd, ASHMEM_PIN, &pin);
}
int ashmem_unpin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
return ioctl(fd, ASHMEM_UNPIN, &pin);
}
int ashmem_get_size_region(int fd)
{
return ioctl(fd, ASHMEM_GET_SIZE, NULL);
}
int ashmem_purge_all(void)
{
const int fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
const int ret = ioctl(fd, ASHMEM_PURGE_ALL_CACHES, 0);
close(fd);
return ret;
}

47
third_party/ashmem/ashmem.h vendored Normal file
View File

@ -0,0 +1,47 @@
/* third_party/ashmem/ashmem.h
**
** Copyright 2008 The Android Open Source Project
**
** This file is dual licensed. It may be redistributed and/or modified
** under the terms of the Apache 2.0 License OR version 2 of the GNU
** General Public License.
*/
#ifndef _THIRD_PARTY_ASHMEM_H
#define _THIRD_PARTY_ASHMEM_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
int ashmem_create_region(const char *name, size_t size);
int ashmem_set_prot_region(int fd, int prot);
int ashmem_get_prot_region(int fd);
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
int ashmem_get_size_region(int fd);
int ashmem_purge_all(void);
#ifdef __cplusplus
}
#endif
#ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
#define ASHMEM_NAME_LEN 256
#define ASHMEM_NAME_DEF "dev/ashmem"
/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
#define ASHMEM_NOT_PURGED 0
#define ASHMEM_WAS_PURGED 1
/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
#define ASHMEM_IS_UNPINNED 0
#define ASHMEM_IS_PINNED 1
#endif /* ! __ASHMEMIOC */
#endif /* _THIRD_PARTY_ASHMEM_H */

View File

@ -0,0 +1,28 @@
diff --git a/third_party/ashmem/ashmem-dev.c b/third_party/ashmem/ashmem-dev.c
index 2303369d8167..52b3f47eeae0 100644
--- a/third_party/ashmem/ashmem-dev.c
+++ b/third_party/ashmem/ashmem-dev.c
@@ -72,6 +72,11 @@ int ashmem_set_prot_region(int fd, int prot)
return ioctl(fd, ASHMEM_SET_PROT_MASK, prot);
}
+int ashmem_get_prot_region(int fd)
+{
+ return ioctl(fd, ASHMEM_GET_PROT_MASK);
+}
+
int ashmem_pin_region(int fd, size_t offset, size_t len)
{
struct ashmem_pin pin = { offset, len };
diff --git a/third_party/ashmem/ashmem.h b/third_party/ashmem/ashmem.h
index 7d411cc064ba..d8afccbd2a6e 100644
--- a/third_party/ashmem/ashmem.h
+++ b/third_party/ashmem/ashmem.h
@@ -18,6 +18,7 @@ extern "C" {
int ashmem_create_region(const char *name, size_t size);
int ashmem_set_prot_region(int fd, int prot);
+int ashmem_get_prot_region(int fd);
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
int ashmem_get_size_region(int fd);

46
third_party/auto/BUILD.gn vendored Normal file
View File

@ -0,0 +1,46 @@
# Copyright 2017 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.
import("//build/config/android/rules.gni")
java_library("auto_common_java") {
java_files = [
"src/common/src/main/java/com/google/auto/common/AnnotationMirrors.java",
"src/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java",
"src/common/src/main/java/com/google/auto/common/MoreTypes.java",
"src/common/src/main/java/com/google/auto/common/SuperficialValidation.java",
"src/common/src/main/java/com/google/auto/common/AnnotationValues.java",
"src/common/src/main/java/com/google/auto/common/MoreElements.java",
"src/common/src/main/java/com/google/auto/common/Overrides.java",
"src/common/src/main/java/com/google/auto/common/Visibility.java",
]
deps = [
"//third_party/guava:guava_java",
]
}
java_library("auto_service_java") {
java_files =
[ "src/service/src/main/java/com/google/auto/service/AutoService.java" ]
deps = [
":auto_common_java",
"//third_party/guava:guava_java",
]
}
java_annotation_processor("auto_service_processor") {
java_files = [
"src/service/src/main/java/com/google/auto/service/processor/AutoServiceProcessor.java",
"src/service/src/main/java/com/google/auto/service/processor/package-info.java",
"src/service/src/main/java/com/google/auto/service/processor/ServicesFiles.java",
]
main_class = "com.google.auto.service.processor.AutoServiceProcessor"
deps = [
":auto_common_java",
":auto_service_java",
"//third_party/guava:guava_java",
]
}

3
third_party/auto/OWNERS vendored Normal file
View File

@ -0,0 +1,3 @@
agrieve@chromium.org
nyquist@chromium.org
wnwen@chromium.org

15
third_party/auto/README.chromium vendored Normal file
View File

@ -0,0 +1,15 @@
Name: Auto
Short Name: auto
URL: https://github.com/google/auto
Version: 8a81a858ae7b78a1aef71ac3905fade0bbd64e82
Date: January 15, 2018
License: Apache 2.0
License File: NOT_SHIPPED
Security Critical: no
Description:
* A collection of source code generators for Java.
* AutoService used for custom plugins in //tools/android/errorprone_plugin.
Local Modifications:
* Add BUILD.gn.

202
third_party/bazel/LICENSE vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

4
third_party/bazel/OWNERS vendored Normal file
View File

@ -0,0 +1,4 @@
agrieve@chromium.org
jbudorick@chromium.org
# COMPONENT: Build

13
third_party/bazel/README.chromium vendored Normal file
View File

@ -0,0 +1,13 @@
Name: (Components of) Bazel
Short Name: (Components of) Bazel
URL: https://github.com/bazelbuild/bazel
License: Apache 2.0
License File: NOT_SHIPPED
Version: Unknown
Security Critical: no
Description:
This directory contains Bazel components used for building Android binaries.
Chromium does not use Bazel itself as the build platform. Please refer to each
sub-directory for information on each Bazel component.

7
third_party/bazel/cipd.yaml vendored Normal file
View File

@ -0,0 +1,7 @@
# Copyright 2017 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.
package: chromium/third_party/bazel
data:
- file: desugar/Desugar.jar

12
third_party/bazel/desugar/BUILD.gn vendored Normal file
View File

@ -0,0 +1,12 @@
# Copyright 2017 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.
import("//build/config/android/rules.gni")
# Provides runtime support for desugar transformations.
java_prebuilt("desugar_runtime_java") {
supports_android = true
jar_path = "Desugar-runtime.jar"
no_build_hooks = true
}

Binary file not shown.

View File

@ -0,0 +1,43 @@
Name: Desugar, transforming Java 8 bytecode to be Java 7 compatible
Short Name: desugar
URL: It's part of Bazel build system (https://github.com/bazelbuild/bazel).
Also, go/desugar for @google.com account owners
Version: 0.10.0
Date: Feb 1, 2018
License: Apache 2.0
Security Critical: no
Description:
Desugar is a Google-developed open-source Java library used by the build process
to transform Java 8 bytecode to Java 7. It is used to enable Java 8 features
such as lambda experssions for Chrome on Android.
Local Modifications:
* Desugar.jar is the "Desugar_deploy.jar" target defined in
[bazel]src/tools/android/java/com/google/devtools/build/android/desugar/BUILD
* Desugar-runtime.jar is derived from Desugar.jar (refer to update
instructions).
Update instructions (requires @google.com account for uploading):
* Check out Bazel from https://github.com/bazelbuild/bazel
* Compile or install Bazel by following instructions on
https://docs.bazel.build/versions/master/install.html
* Build Desugar_deploy.jar by running
bazel build //src/tools/android/java/com/google/devtools/build/android/desugar:Desugar_deploy.jar
* Move Desugar_deploy.jar to location within Chromium:
rm $CHROMIUM_SRC/third_party/bazel/desugar/Desugar.jar
mv bazel-bin/src/tools/android/java/com/google/devtools/build/android/desugar/Desugar_deploy.jar $CHROMIUM_SRC/third_party/bazel/desugar/Desugar.jar
* Update Desugar-runtime.jar:
unzip Desugar.jar "com/google/devtools/build/android/desugar/runtime*"
zip -rD0 Desugar-runtime.jar com
rm -r com
* Perform a sanity check of chrome_public_apk:
ninja chrome_public_apk
bin/chrome_public_apk run
* Update this README.chromium (Version & Date)
* Upload new jar to CIPD:
cd third_party/bazel
VERSION=$(grep Version -m1 desugar/README.chromium | cut -d' ' -f2)
cipd create --pkg-def cipd.yaml -tag version:$VERSION
* Update revision in //build/cipd/android/android.ensure (soon to be right in
//DEPS)

340
third_party/binutils/LICENSE vendored Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1 @@
ee534836babdf330503ad62934a1975fc9b6fba9

View File

@ -0,0 +1 @@
5230f6066998df2f4d61d5fa586152ab20cca300

3
third_party/binutils/OWNERS vendored Normal file
View File

@ -0,0 +1,3 @@
thakis@chromium.org
thestig@chromium.org
thomasanderson@chromium.org

39
third_party/binutils/README.chromium vendored Normal file
View File

@ -0,0 +1,39 @@
Name: binutils
URL: http://www.gnu.org/software/binutils/
Version: 2.29.1
License: GPL v2
License File: NOT_SHIPPED
Security Critical: no
Description:
This directory contains i386 and amd64 binaries of the binutils tools
(including gold linker).
They were built from binutils-2.29.1 using the "build-all.sh" script on Debian
Testing.
The script creates chroots for 32bit and 64bit Ubuntu Xenial and then builds
binutils inside the roots.
Local patches:
* (build-all.sh|build-one.sh|upload.sh) scripts for building the binutils
binaries and uploading them to Google storage.
Upgrading:
To upgrade binutils, use the following steps:
* Update build-all.sh with the new binutil version.
* Remove any patches which have been merged upstream from build-all.sh
* Update this README.chromium file
* Run build-all.sh
* Run upload.sh. Note: you will need write access to
gs://chromium-binutils bucket on Google Cloud Storage. To get the
access, subscribe to the internal chrome-team mailing list.
* Wait for goma to have new binutils deployed (see http://go/ma).
Please notify {ukai,yyanagisawa,shinyak}@chromium.org and await
confirmation.
* Commit the change
See https://codereview.chromium.org/1368233002/ for an example upgrade.

113
third_party/binutils/build-all.sh vendored Executable file
View File

@ -0,0 +1,113 @@
#!/bin/sh
# Copyright 2014 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.
# Script to build binutils for both i386 and AMD64 Linux architectures.
# Must be run on an AMD64 supporting machine which has debootstrap and sudo
# installed.
# Uses Ubuntu Xenial chroots as build environment.
set -e
set -u
if [ x"$(whoami)" = x"root" ]; then
echo "Script must not be run as root."
exit 1
fi
sudo -v
OUTPUTDIR="${1:-$PWD/output-$(date +%Y%m%d-%H%M%S)}"
if [ ! -d "$OUTPUTDIR" ]; then
mkdir -p "$OUTPUTDIR"
fi
# Download the source
VERSION=2.29.1
wget -c http://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.bz2
# Verify the signature
wget -c -q http://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.bz2.sig
if ! gpg --verify binutils-$VERSION.tar.bz2.sig; then
echo "GPG Signature failed to verify."
echo ""
echo "You may need to import the vendor GPG key with:"
echo "# gpg --keyserver hkp://pgp.mit.edu:80 --recv-key 4AE55E93 DD9E3C4F"
exit 1
fi
# Extract the source
rm -rf binutils-$VERSION
tar jxf binutils-$VERSION.tar.bz2
for ARCH in i386 amd64; do
CHROOT_DIR="xenial-chroot-$ARCH"
if [ ! -d ${CHROOT_DIR} ]; then
# Refresh sudo credentials
sudo -v
CHROOT_TEMPDIR=$(mktemp -d ${CHROOT_DIR}.XXXXXX)
# Create the chroot
echo ""
echo "Building chroot for $ARCH"
echo "============================="
sudo debootstrap \
--arch=$ARCH \
--include=build-essential,flex,bison \
xenial ${CHROOT_TEMPDIR}
echo "============================="
mv ${CHROOT_TEMPDIR} ${CHROOT_DIR}
fi
BUILDDIR=${CHROOT_DIR}/build
# Clean up any previous failed build attempts inside chroot
if [ -d "$BUILDDIR" ]; then
sudo rm -rf "$BUILDDIR"
fi
# Copy data into the chroot
sudo mkdir -p "$BUILDDIR"
sudo cp -a binutils-$VERSION "$BUILDDIR"
sudo cp -a build-one.sh "$BUILDDIR"
# Do the build
PREFIX=
case $ARCH in
i386)
PREFIX="setarch linux32"
ARCHNAME=i686-pc-linux-gnu
;;
amd64)
PREFIX="setarch linux64"
ARCHNAME=x86_64-pc-linux-gnu
;;
esac
echo ""
echo "Building binutils for $ARCH"
LOGFILE="$OUTPUTDIR/build-$ARCH.log"
if ! sudo $PREFIX chroot ${CHROOT_DIR} /build/build-one.sh \
/build/binutils-$VERSION > $LOGFILE 2>&1; then
echo "Build failed! See $LOGFILE for details."
exit 1
fi
# Copy data out of the chroot
sudo chown -R $(whoami) "$BUILDDIR/output/"
# Strip the output binaries
strip "$BUILDDIR/output/$ARCHNAME/bin/"*
# Copy them out of the chroot
cp -a "$BUILDDIR/output/$ARCHNAME" "$OUTPUTDIR"
# Clean up chroot
sudo rm -rf "$BUILDDIR"
done
echo "Check you are happy with the binaries in"
echo " $OUTPUTDIR"
echo "Then"
echo " * upload to Google Storage using the upload.sh script"
echo " * roll dependencies"

32
third_party/binutils/build-one.sh vendored Executable file
View File

@ -0,0 +1,32 @@
#!/bin/sh
# Copyright 2014 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.
# Script to build binutils found in /build/binutils-XXXX when inside a chroot.
# Don't call this script yourself, instead use the build-all.sh script.
set -e
set -x
if [ -z "$1" ]; then
echo "Directory of binutils not given."
exit 1
fi
cd "$1"
./configure \
--enable-deterministic-archives \
--enable-gold=default \
--enable-plugins \
--enable-threads \
--prefix=/build/output
make -j8 all
echo
echo "= binutils/config.h ================================================"
cat binutils/config.h
echo "===================================================================="
echo
make install

130
third_party/binutils/download.py vendored Executable file
View File

@ -0,0 +1,130 @@
#!/usr/bin/env python
# Copyright 2014 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.
# vim: set ts=2 sw=2 et sts=2 ai:
"""Minimal tool to download binutils from Google storage.
TODO(mithro): Replace with generic download_and_extract tool.
"""
import argparse
import os
import platform
import re
import shutil
import subprocess
import sys
BINUTILS_DIR = os.path.abspath(os.path.dirname(__file__))
BINUTILS_FILE = 'binutils.tar.bz2'
BINUTILS_TOOLS = ['bin/ld.gold', 'bin/objcopy', 'bin/objdump']
BINUTILS_OUT = 'Release'
DETECT_HOST_ARCH = os.path.abspath(os.path.join(
BINUTILS_DIR, '../../build/detect_host_arch.py'))
def ReadFile(filename):
with file(filename, 'r') as f:
return f.read().strip()
def WriteFile(filename, content):
assert not os.path.exists(filename)
with file(filename, 'w') as f:
f.write(content)
f.write('\n')
def GetArch():
gyp_host_arch = re.search(
'host_arch=(\S*)', os.environ.get('GYP_DEFINES', ''))
if gyp_host_arch:
arch = gyp_host_arch.group(1)
# This matches detect_host_arch.py.
if arch == 'x86_64':
return 'x64'
return arch
return subprocess.check_output(['python', DETECT_HOST_ARCH]).strip()
def FetchAndExtract(arch):
archdir = os.path.join(BINUTILS_DIR, 'Linux_' + arch)
tarball = os.path.join(archdir, BINUTILS_FILE)
outdir = os.path.join(archdir, BINUTILS_OUT)
sha1file = tarball + '.sha1'
if not os.path.exists(sha1file):
print "WARNING: No binutils found for your architecture (%s)!" % arch
return 0
checksum = ReadFile(sha1file)
stampfile = tarball + '.stamp'
if os.path.exists(stampfile):
if (os.path.exists(tarball) and
os.path.exists(outdir) and
checksum == ReadFile(stampfile)):
return 0
else:
os.unlink(stampfile)
print "Downloading", tarball
subprocess.check_call([
'download_from_google_storage',
'--no_resume',
'--no_auth',
'--bucket', 'chromium-binutils',
'-s', sha1file])
assert os.path.exists(tarball)
if os.path.exists(outdir):
shutil.rmtree(outdir)
assert not os.path.exists(outdir)
os.makedirs(outdir)
assert os.path.exists(outdir)
print "Extracting", tarball
subprocess.check_call(['tar', 'axf', tarball], cwd=outdir)
for tool in BINUTILS_TOOLS:
assert os.path.exists(os.path.join(outdir, tool))
WriteFile(stampfile, checksum)
return 0
def main(args):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--ignore-if-arch', metavar='ARCH',
action='append', default=[],
help='Do nothing on host architecture ARCH')
options = parser.parse_args(args)
if not sys.platform.startswith('linux'):
return 0
arch = GetArch()
if arch in options.ignore_if_arch:
return 0
if arch == 'x64':
return FetchAndExtract(arch)
if arch == 'ia32':
ret = FetchAndExtract(arch)
if ret != 0:
return ret
# Fetch the x64 toolchain as well for official bots with 64-bit kernels.
return FetchAndExtract('x64')
print "Host architecture %s is not supported." % arch
return 1
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

68
third_party/binutils/upload.sh vendored Executable file
View File

@ -0,0 +1,68 @@
#!/bin/sh
# Copyright 2014 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.
# Upload the generated output to Google storage.
set -e
if [ ! -d "$1" ]; then
echo "update.sh <output directory from build-all.sh>"
exit 1
fi
if echo "$PWD" | grep -qE "/src/third_party/binutils$"; then
echo -n
else
echo "update.sh should be run in src/third_party/binutils"
exit 1
fi
if [ ! -f ~/.boto ]; then
echo "You need to run 'gsutil config' to set up authentication before running this script."
exit 1
fi
for DIR in $1/*; do
# Skip if not directory
if [ ! -d "$DIR" ]; then
continue
fi
case "$DIR" in
*/i686-pc-linux-gnu)
export ARCH="Linux_ia32"
;;
*/x86_64-pc-linux-gnu)
export ARCH="Linux_x64"
;;
*)
echo "Unknown architecture directory $DIR"
exit 1
;;
esac
if [ ! -d "$ARCH" ]; then
mkdir -p "$ARCH"
fi
BINUTILS_TAR_BZ2="$ARCH/binutils.tar.bz2"
FULL_BINUTILS_TAR_BZ2="$PWD/$BINUTILS_TAR_BZ2"
if [ -f "${BINUTILS_TAR_BZ2}.sha1" ]; then
rm "${BINUTILS_TAR_BZ2}.sha1"
fi
(cd "$DIR"; tar jcf "$FULL_BINUTILS_TAR_BZ2" .)
upload_to_google_storage.py --bucket chromium-binutils "$BINUTILS_TAR_BZ2"
git add -f "${BINUTILS_TAR_BZ2}.sha1"
done
echo "Please commit the new .sha1 to the Chromium repository"
echo "# git commit"
echo ""
echo "Make sure goma is updated with the new binutils *before* landing."
echo " Notify {ukai,yyanagisawa,shinyak}@chromium.org with the .sha1 files"
echo " and await confirmation."

1
third_party/boringssl/.clang-format vendored Normal file
View File

@ -0,0 +1 @@
DisableFormat: true

Some files were not shown because too many files have changed in this diff Show More