mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-20 18:53:47 +00:00
Merge master e616638c9d87 into doc
This commit is contained in:
commit
6da4a15869
2
DEPS
2
DEPS
@ -25,7 +25,7 @@ deps = {
|
||||
'93cc6e2c23e4d5ebd179f388e67aa907d0dfd43d',
|
||||
'crashpad/third_party/mini_chromium/mini_chromium':
|
||||
Var('chromium_git') + '/chromium/mini_chromium@' +
|
||||
'88e0a3e1a965c698d7ead8bcfc0cfb6aacdc3524',
|
||||
'8e8d3cc9a245f1bf63296e97fb6ac1c90f6d86f5',
|
||||
'buildtools':
|
||||
Var('chromium_git') + '/chromium/buildtools.git@' +
|
||||
'f8fc76ea5ce4a60cda2fa5d7df3d4a62935b3113',
|
||||
|
@ -38,7 +38,7 @@ present in the `$PATH` environment variable:
|
||||
|
||||
* Chromium’s
|
||||
https://dev.chromium.org/developers/how-tos/depottools[depot_tools].
|
||||
* http://git-scm.com/[Git]. This is provided by Xcode on Mac OS X and by
|
||||
* https://git-scm.com/[Git]. This is provided by Xcode on Mac OS X and by
|
||||
depot_tools on Windows.
|
||||
* https://www.python.org/[Python]. This is provided by the operating system on
|
||||
Mac OS X, and by depot_tools on Windows.
|
||||
@ -69,8 +69,8 @@ $ *cd ~/crashpad*
|
||||
$ *fetch crashpad*
|
||||
----
|
||||
|
||||
`fetch crashpad` performs the initial `gclient sync`, establishing a
|
||||
fully-functional local checkout.
|
||||
`fetch crashpad` performs the initial `git clone` and `gclient sync`,
|
||||
establishing a fully-functional local checkout.
|
||||
|
||||
=== Subsequent Checkouts
|
||||
|
||||
@ -84,10 +84,10 @@ $ *gclient sync*
|
||||
== Building
|
||||
|
||||
Crashpad uses https://gyp.gsrc.io/[GYP] to generate
|
||||
https://martine.github.io/ninja/[Ninja] build files. The build is described by
|
||||
`.gyp` files throughout the Crashpad source code tree. The
|
||||
`build/gyp_crashpad.py` script runs GYP properly for Crashpad, and is also
|
||||
called when you run `fetch crashpad`, `gclient sync`, or `gclient runhooks`.
|
||||
https://ninja-build.org/[Ninja] build files. The build is described by `.gyp`
|
||||
files throughout the Crashpad source code tree. The `build/gyp_crashpad.py`
|
||||
script runs GYP properly for Crashpad, and is also called when you run `fetch
|
||||
crashpad`, `gclient sync`, or `gclient runhooks`.
|
||||
|
||||
The Ninja build files and build output are in the `out` directory. Both debug-
|
||||
and release-mode configurations are available. The examples below show the debug
|
||||
@ -104,6 +104,80 @@ Ninja is part of the
|
||||
https://dev.chromium.org/developers/how-tos/depottools[depot_tools]. There’s no
|
||||
need to install it separately.
|
||||
|
||||
=== Android
|
||||
|
||||
Crashpad’s Android port is in its early stages. This build relies on
|
||||
cross-compilation. It’s possible to develop Crashpad for Android on any platform
|
||||
that the https://developer.android.com/ndk/[Android NDK (Native Development
|
||||
Kit)] runs on.
|
||||
|
||||
If it’s not already present on your system,
|
||||
https://developer.android.com/ndk/downloads/[download the NDK package for your
|
||||
system] and expand it to a suitable location. These instructions assume that
|
||||
it’s been expanded to `~/android-ndk-r13`.
|
||||
|
||||
To build Crashpad, portions of the NDK must be reassembled into a
|
||||
https://developer.android.com/ndk/guides/standalone_toolchain.html[standalone
|
||||
toolchain]. This is a repackaged subset of the NDK suitable for cross-compiling
|
||||
for a single Android architecture (such as `arm`, `arm64`, `x86`, and `x86_64`)
|
||||
targeting a specific
|
||||
https://source.android.com/source/build-numbers.html[Android API level]. The
|
||||
standalone toolchain only needs to be built from the NDK one time for each set
|
||||
of options desired. To build a standalone toolchain targeting 64-bit ARM and API
|
||||
level 21 (Android 5.0 “Lollipop”), run:
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
$ *cd ~*
|
||||
$ *python android-ndk-r13/build/tools/make_standalone_toolchain.py \
|
||||
--arch=arm64 --api=21 --install-dir=android-ndk-r13_arm64_api21*
|
||||
----
|
||||
|
||||
Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for
|
||||
32-bit platforms. See Chrome’s
|
||||
https://chromium.googlesource.com/chromium/src/+/master/build/config/android/config.gni[`build/config/android/config.gni`]
|
||||
which sets `_android_api_level` and `_android64_api_level`.
|
||||
|
||||
To configure a Crashpad build for Android using this standalone toolchain,
|
||||
set several environment variables directing the build to the standalone
|
||||
toolchain, along with GYP options to identify an Android build. This must be
|
||||
done after any `gclient sync`, or instead of any `gclient runhooks` operation.
|
||||
The environment variables only need to be set for this `gyp_crashpad.py`
|
||||
invocation, and need not be permanent.
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
$ *cd \~/crashpad/crashpad*
|
||||
$ *CC_target=\~/android-ndk-r13_arm64_api21/bin/clang \
|
||||
CXX_target=\~/android-ndk-r13_arm64_api21/bin/clang++ \
|
||||
AR_target=\~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-ar \
|
||||
NM_target=\~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-nm \
|
||||
READELF_target=~/android-ndk-r13_arm64_api21/bin/aarch64-linux-android-readelf \
|
||||
python build/gyp_crashpad.py \
|
||||
-DOS=android -Dtarget_arch=arm64 -Dclang=1 \
|
||||
--generator-output=out_android_arm64_api21 -f ninja-android*
|
||||
----
|
||||
|
||||
Target “triplets” to use for `ar`, `nm`, and `readelf` are:
|
||||
|
||||
[width="40%",cols="1,3",frame="topbot"]
|
||||
|===
|
||||
|`arm` |`arm-linux-androideabi`
|
||||
|`arm64` |`aarch64-linux-android`
|
||||
|`x86` |`i686-linux-android`
|
||||
|`x86_64` |`x86_64-linux-android`
|
||||
|===
|
||||
|
||||
The port is incomplete, but targets known to be working include `crashpad_util`,
|
||||
`crashpad_test`, and `crashpad_test_test`. This list will grow over time. To
|
||||
build, direct `ninja` to the specific `out` directory chosen by
|
||||
`--generator-output` above.
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
$ *ninja -C out_android_arm64_api21/out/Debug crashpad_test_test*
|
||||
----
|
||||
|
||||
== Testing
|
||||
|
||||
Crashpad uses https://github.com/google/googletest/[Google Test] as its
|
||||
@ -130,6 +204,39 @@ $ *cd ~/crashpad/crashpad*
|
||||
$ *python build/run_tests.py Debug*
|
||||
----
|
||||
|
||||
=== Android
|
||||
|
||||
To test on Android, use
|
||||
https://developer.android.com/studio/command-line/adb.html[ADB (Android Debug
|
||||
Bridge)] to `adb push` test executables and test data to a device or emulator,
|
||||
then use `adb shell` to get a shell to run the test executables from. ADB is
|
||||
part of the https://developer.android.com/sdk/[Android SDK]. Note that it is
|
||||
sufficient to install just the command-line tools. The entire Android Studio IDE
|
||||
is not necessary to obtain ADB.
|
||||
|
||||
This example runs `crashpad_test_test` on a device. This test executable has a
|
||||
run-time dependency on a second executable and a test data file, which are also
|
||||
transferred to the device prior to running the test.
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
$ *cd ~/crashpad/crashpad*
|
||||
$ *adb push out_android_arm64_api21/out/Debug/crashpad_test_test /data/local/tmp/*
|
||||
[100%] /data/local/tmp/crashpad_test_test
|
||||
$ *adb push \
|
||||
out_android_arm64_api21/out/Debug/crashpad_test_test_multiprocess_exec_test_child \
|
||||
/data/local/tmp/*
|
||||
[100%] /data/local/tmp/crashpad_test_test_multiprocess_exec_test_child
|
||||
$ *adb shell mkdir -p /data/local/tmp/crashpad_test_data_root/test*
|
||||
$ *adb push test/paths_test_data_root.txt \
|
||||
/data/local/tmp/crashpad_test_data_root/test/*
|
||||
[100%] /data/local/tmp/crashpad_test_data_root/test/paths_test_data_root.txt
|
||||
$ *adb shell*
|
||||
device:/ $ *cd /data/local/tmp*
|
||||
device:/data/local/tmp $ *CRASHPAD_TEST_DATA_ROOT=crashpad_test_data_root \
|
||||
./crashpad_test_test*
|
||||
----
|
||||
|
||||
== Contributing
|
||||
|
||||
Crashpad’s contribution process is very similar to
|
||||
@ -139,9 +246,9 @@ process].
|
||||
=== Code Review
|
||||
|
||||
A code review must be conducted for every change to Crashpad’s source code. Code
|
||||
review is conducted on https://codereview.chromium.org/[Chromium’s Rietveld]
|
||||
system, and all code reviews must be sent to an appropriate reviewer, with a Cc
|
||||
sent to
|
||||
review is conducted on https://chromium-review.googlesource.com/[Chromium’s
|
||||
Gerrit] system, and all code reviews must be sent to an appropriate reviewer,
|
||||
with a Cc sent to
|
||||
https://groups.google.com/a/chromium.org/group/crashpad-dev[crashpad-dev]. The
|
||||
`codereview.settings` file specifies this environment to `git-cl`.
|
||||
|
||||
@ -159,14 +266,18 @@ $ *git commit*
|
||||
$ *git cl upload*
|
||||
----
|
||||
|
||||
Uploading a patch to Rietveld does not automatically request a review. You must
|
||||
select a reviewer and mail your request to them (with a Cc to crashpad-dev) from
|
||||
the Rietveld issue page after running `git cl upload`. If you have lost track of
|
||||
the issue page, `git cl issue` will remind you of its URL. Alternatively, you
|
||||
can request review when uploading to Rietveld by using `git cl upload
|
||||
--send-mail`
|
||||
The https://polygerrit.appspot.com/[PolyGerrit interface] to Gerrit, undergoing
|
||||
active development, is recommended. To switch from the classic GWT-based Gerrit
|
||||
UI to PolyGerrit, click the PolyGerrit link in a Gerrit review page’s footer.
|
||||
|
||||
Git branches maintain their association with Rietveld issues, so if you need to
|
||||
Uploading a patch to Gerrit does not automatically request a review. You must
|
||||
select a reviewer on the Gerrit review page after running `git cl upload`. This
|
||||
action notifies your reviewer of the code review request. If you have lost track
|
||||
of the review page, `git cl issue` will remind you of its URL. Alternatively,
|
||||
you can request review when uploading to Gerrit by using `git cl upload
|
||||
--send-mail`.
|
||||
|
||||
Git branches maintain their association with Gerrit reviews, so if you need to
|
||||
make changes based on review feedback, you can do so on the correct Git branch,
|
||||
committing your changes locally with `git commit`. You can then upload a new
|
||||
patch set with `git cl upload` and let your reviewer know you’ve addressed the
|
||||
@ -174,8 +285,8 @@ feedback.
|
||||
|
||||
=== Landing Changes
|
||||
|
||||
After code review is complete and “LGTM” (“looks good to me”) has been received
|
||||
from all reviewers, project members can commit the patch themselves:
|
||||
After code review is complete and “Code-Review: +1”) has been received from all
|
||||
reviewers, project members can commit the patch themselves:
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
@ -184,19 +295,14 @@ $ *git checkout work_branch*
|
||||
$ *git cl land*
|
||||
----
|
||||
|
||||
Alternatively, patches can be committed by clicking the “Submit” button in the
|
||||
Gerrit UI.
|
||||
|
||||
Crashpad does not currently have a
|
||||
https://dev.chromium.org/developers/testing/commit-queue[commit queue], so
|
||||
contributors that are not project members will have to ask a project member to
|
||||
contributors who are not project members will have to ask a project member to
|
||||
commit the patch for them. Project members can commit changes on behalf of
|
||||
external contributors by patching the change into a local branch and landing it:
|
||||
|
||||
[subs="verbatim,quotes"]
|
||||
----
|
||||
$ *cd ~/crashpad/crashpad*
|
||||
$ *git checkout -b for_external_contributor origin/master*
|
||||
$ *git cl patch 12345678* _# 12345678 is the Rietveld issue number_
|
||||
$ *git cl land -c \'External Contributor <external@contributor.org>'*
|
||||
----
|
||||
external contributors by clicking the “Submit” button in the Gerrit UI.
|
||||
|
||||
=== External Contributions
|
||||
|
||||
|
@ -31,7 +31,7 @@ https://chromium.googlesource.com/chromium/src/\+/cfa5b01bb1d06bf96967bd37e21a44
|
||||
|
||||
Initial work on a Crashpad client for
|
||||
https://crashpad.chromium.org/bug/30[Android] has begun. This is currently in
|
||||
the design phase.
|
||||
the early implementation phase.
|
||||
|
||||
== Future
|
||||
|
||||
|
@ -207,9 +207,12 @@ void CrashReportUploadThread::ProcessPendingReport(
|
||||
// hour, and retire reports that would exceed this limit or for which the
|
||||
// upload fails on the first attempt.
|
||||
//
|
||||
// If upload was requested explicitly (i.e. by user action), we do not
|
||||
// throttle the upload.
|
||||
//
|
||||
// TODO(mark): Provide a proper rate-limiting strategy and allow for failed
|
||||
// upload attempts to be retried.
|
||||
if (rate_limit_) {
|
||||
if (!report.upload_explicitly_requested && rate_limit_) {
|
||||
time_t last_upload_attempt_time;
|
||||
if (settings->GetLastUploadAttemptTime(&last_upload_attempt_time)) {
|
||||
time_t now = time(nullptr);
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "util/misc/scoped_forbid_return.h"
|
||||
#include "util/posix/close_multiple.h"
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#include <stdio_ext.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
@ -78,8 +82,14 @@ void MultiprocessExec::MultiprocessChild() {
|
||||
ASSERT_NE(read_handle, STDOUT_FILENO);
|
||||
ASSERT_EQ(STDIN_FILENO, fileno(stdin));
|
||||
|
||||
int rv = fpurge(stdin);
|
||||
int rv;
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
__fpurge(stdin);
|
||||
#else
|
||||
rv = fpurge(stdin);
|
||||
ASSERT_EQ(0, rv) << ErrnoMessage("fpurge");
|
||||
#endif
|
||||
|
||||
rv = HANDLE_EINTR(dup2(read_handle, STDIN_FILENO));
|
||||
ASSERT_EQ(STDIN_FILENO, rv) << ErrnoMessage("dup2");
|
||||
|
@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
@ -37,9 +38,13 @@ int main(int argc, char* argv[]) {
|
||||
// Make sure that there’s nothing open at any FD higher than 3. All FDs other
|
||||
// than stdin, stdout, and stderr should have been closed prior to or at
|
||||
// exec().
|
||||
int max_fd = std::max(static_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX);
|
||||
max_fd = std::max(max_fd, getdtablesize());
|
||||
for (int fd = STDERR_FILENO + 1; fd < max_fd; ++fd) {
|
||||
rlimit rlimit_nofile;
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlimit_nofile) != 0) {
|
||||
abort();
|
||||
}
|
||||
for (int fd = STDERR_FILENO + 1;
|
||||
fd < static_cast<int>(rlimit_nofile.rlim_cur);
|
||||
++fd) {
|
||||
if (close(fd) == 0 || errno != EBADF) {
|
||||
abort();
|
||||
}
|
||||
|
@ -14,8 +14,8 @@
|
||||
|
||||
#include "test/multiprocess.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
|
62
test/paths_linux.cc
Normal file
62
test/paths_linux.cc
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright 2016 The Crashpad Authors. 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.
|
||||
|
||||
#include "test/paths.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
// static
|
||||
base::FilePath Paths::Executable() {
|
||||
// Linux does not provide a straightforward way to size the buffer before
|
||||
// calling readlink(). Normally, the st_size field returned by lstat() could
|
||||
// be used, but this is usually zero for things in /proc.
|
||||
//
|
||||
// The /proc filesystem does not provide any way to read “exe” links for
|
||||
// pathnames longer than a page. See linux-4.4.27/fs/proc/base.c
|
||||
// do_proc_readlink(), which allocates a single page to receive the path
|
||||
// string. Coincidentally, the page size and PATH_MAX are normally the same
|
||||
// value, although neither is strictly a limit on the length of a pathname.
|
||||
//
|
||||
// On Android, the smaller of the page size and PATH_MAX actually does serve
|
||||
// as an effective limit on the length of an executable’s pathname. See
|
||||
// Android 7.0.0 bionic/linker/linker.cpp get_executable_path(), which aborts
|
||||
// via __libc_fatal() if the “exe” link can’t be read into a PATH_MAX-sized
|
||||
// buffer.
|
||||
std::string exe_path(std::max(implicit_cast<size_t>(sysconf(_SC_PAGESIZE)),
|
||||
implicit_cast<size_t>(PATH_MAX)),
|
||||
std::string::value_type());
|
||||
ssize_t exe_path_len =
|
||||
readlink("/proc/self/exe", &exe_path[0], exe_path.size());
|
||||
if (exe_path_len < 0) {
|
||||
PLOG(FATAL) << "readlink";
|
||||
} else if (static_cast<size_t>(exe_path_len) >= exe_path.size()) {
|
||||
LOG(FATAL) << "readlink";
|
||||
}
|
||||
|
||||
exe_path.resize(exe_path_len);
|
||||
return base::FilePath(exe_path);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
@ -26,10 +26,11 @@ namespace test {
|
||||
base::FilePath Paths::Executable() {
|
||||
uint32_t executable_length = 0;
|
||||
_NSGetExecutablePath(nullptr, &executable_length);
|
||||
DCHECK_GT(executable_length, 1u);
|
||||
CHECK_GT(executable_length, 1u);
|
||||
|
||||
std::string executable_path(executable_length - 1, std::string::value_type());
|
||||
int rv = _NSGetExecutablePath(&executable_path[0], &executable_length);
|
||||
DCHECK_EQ(rv, 0);
|
||||
CHECK_EQ(rv, 0);
|
||||
|
||||
return base::FilePath(executable_path);
|
||||
}
|
||||
|
@ -16,13 +16,17 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
// static
|
||||
base::FilePath Paths::Executable() {
|
||||
wchar_t executable_path[_MAX_PATH];
|
||||
GetModuleFileName(nullptr, executable_path, sizeof(executable_path));
|
||||
unsigned int len =
|
||||
GetModuleFileName(nullptr, executable_path, arraysize(executable_path));
|
||||
PCHECK(len != 0 && len < arraysize(executable_path)) << "GetModuleFileName";
|
||||
return base::FilePath(executable_path);
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,12 @@
|
||||
#include "test/scoped_temp_dir.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
|
||||
@ -33,9 +35,25 @@ void ScopedTempDir::Rename() {
|
||||
|
||||
// static
|
||||
base::FilePath ScopedTempDir::CreateTemporaryDirectory() {
|
||||
char dir_template[] = "/tmp/org.chromium.crashpad.test.XXXXXX";
|
||||
PCHECK(mkdtemp(dir_template)) << "mkdtemp " << dir_template;
|
||||
return base::FilePath(dir_template);
|
||||
char* tmpdir = getenv("TMPDIR");
|
||||
std::string dir;
|
||||
if (tmpdir && tmpdir[0] != '\0') {
|
||||
dir.assign(tmpdir);
|
||||
} else {
|
||||
#if defined(OS_ANDROID)
|
||||
dir.assign("/data/local/tmp");
|
||||
#else
|
||||
dir.assign("/tmp");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dir[dir.size() - 1] != '/') {
|
||||
dir.append(1, '/');
|
||||
}
|
||||
dir.append("org.chromium.crashpad.test.XXXXXX");
|
||||
|
||||
PCHECK(mkdtemp(&dir[0])) << "mkdtemp " << dir;
|
||||
return base::FilePath(dir);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -47,6 +47,7 @@
|
||||
'multiprocess_posix.cc',
|
||||
'paths.cc',
|
||||
'paths.h',
|
||||
'paths_linux.cc',
|
||||
'paths_mac.cc',
|
||||
'paths_win.cc',
|
||||
'scoped_temp_dir.cc',
|
||||
@ -76,6 +77,13 @@
|
||||
},
|
||||
}],
|
||||
],
|
||||
'target_conditions': [
|
||||
['OS=="android"', {
|
||||
'sources/': [
|
||||
['include', '^paths_linux\\.cc$'],
|
||||
],
|
||||
}],
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -73,9 +73,19 @@ bool WeakFileHandleFileWriter::WriteIoVec(std::vector<WritableIoVec>* iovecs) {
|
||||
iovec* iov = reinterpret_cast<iovec*>(&(*iovecs)[0]);
|
||||
size_t remaining_iovecs = iovecs->size();
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// Android does not expose the IOV_MAX macro, but makes its value available
|
||||
// via sysconf(). See Android 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf().
|
||||
// Bionic defines IOV_MAX at bionic/libc/include/limits.h, but does not ship
|
||||
// this file to the NDK as <limits.h>, substituting
|
||||
// bionic/libc/include/bits/posix_limits.h.
|
||||
const size_t kIovMax = sysconf(_SC_IOV_MAX);
|
||||
#else
|
||||
const size_t kIovMax = IOV_MAX;
|
||||
#endif
|
||||
|
||||
while (size > 0) {
|
||||
size_t writev_iovec_count =
|
||||
std::min(remaining_iovecs, implicit_cast<size_t>(IOV_MAX));
|
||||
size_t writev_iovec_count = std::min(remaining_iovecs, kIovMax);
|
||||
ssize_t written =
|
||||
HANDLE_EINTR(writev(file_handle_, iov, writev_iovec_count));
|
||||
if (written < 0) {
|
||||
|
@ -14,11 +14,11 @@
|
||||
|
||||
#include "util/misc/clock.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/format_macros.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
@ -85,8 +85,8 @@ TEST(Clock, SleepNanoseconds) {
|
||||
|
||||
for (size_t index = 0; index < arraysize(kTestData); ++index) {
|
||||
const uint64_t nanoseconds = kTestData[index];
|
||||
SCOPED_TRACE(
|
||||
base::StringPrintf("index %zu, nanoseconds %llu", index, nanoseconds));
|
||||
SCOPED_TRACE(base::StringPrintf(
|
||||
"index %zu, nanoseconds %" PRIu64, index, nanoseconds));
|
||||
|
||||
TestSleepNanoseconds(nanoseconds);
|
||||
}
|
||||
|
@ -18,6 +18,16 @@
|
||||
#include "base/metrics/sparse_histogram.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#define METRICS_OS_NAME "Mac"
|
||||
#elif defined(OS_WIN)
|
||||
#define METRICS_OS_NAME "Win"
|
||||
#elif defined(OS_ANDROID)
|
||||
#define METRICS_OS_NAME "Android"
|
||||
#elif defined(OS_LINUX)
|
||||
#define METRICS_OS_NAME "Linux"
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
@ -79,12 +89,7 @@ void Metrics::ExceptionCaptureResult(CaptureResult result) {
|
||||
|
||||
// static
|
||||
void Metrics::ExceptionCode(uint32_t exception_code) {
|
||||
#if defined(OS_WIN)
|
||||
static const char kExceptionCodeString[] = "Crashpad.ExceptionCode.Win";
|
||||
#elif defined(OS_MACOSX)
|
||||
static const char kExceptionCodeString[] = "Crashpad.ExceptionCode.Mac";
|
||||
#endif
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY(kExceptionCodeString,
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY("Crashpad.ExceptionCode." METRICS_OS_NAME,
|
||||
static_cast<int32_t>(exception_code));
|
||||
}
|
||||
|
||||
@ -94,15 +99,9 @@ void Metrics::ExceptionEncountered() {
|
||||
}
|
||||
|
||||
void Metrics::HandlerCrashed(uint32_t exception_code) {
|
||||
#if defined(OS_WIN)
|
||||
static const char kExceptionCodeString[] =
|
||||
"Crashpad.HandlerCrash.ExceptionCode.Win";
|
||||
#elif defined(OS_MACOSX)
|
||||
static const char kExceptionCodeString[] =
|
||||
"Crashpad.HandlerCrash.ExceptionCode.Mac";
|
||||
#endif
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY(kExceptionCodeString,
|
||||
static_cast<int32_t>(exception_code));
|
||||
UMA_HISTOGRAM_SPARSE_SLOWLY(
|
||||
"Crashpad.HandlerCrash.ExceptionCode." METRICS_OS_NAME,
|
||||
static_cast<int32_t>(exception_code));
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/sys_byteorder.h"
|
||||
@ -109,6 +110,16 @@ bool UUID::InitializeWithNew() {
|
||||
return false;
|
||||
}
|
||||
InitializeFromSystemUUID(&system_uuid);
|
||||
return true;
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// Linux does not provide a UUID generator in a widely-available system
|
||||
// library. uuid_generate() from libuuid is not available everywhere.
|
||||
base::RandBytes(this, sizeof(*this));
|
||||
|
||||
// Set six bits per RFC 4122 §4.4 to identify this as a pseudo-random UUID.
|
||||
data_3 = (4 << 12) | (data_3 & 0x0fff); // §4.1.3
|
||||
data_4[0] = 0x80 | (data_4[0] & 0x3f); // §4.1.1
|
||||
|
||||
return true;
|
||||
#else
|
||||
#error Port.
|
||||
|
@ -122,7 +122,7 @@ TEST(CheckedAddressRange, IsValid) {
|
||||
for (size_t index = 0; index < arraysize(kTestData); ++index) {
|
||||
const TestData& testcase = kTestData[index];
|
||||
SCOPED_TRACE(base::StringPrintf("index %" PRIuS
|
||||
", base 0x%llx, size 0x%llx",
|
||||
", base 0x%" PRIx64 ", size 0x%" PRIx64,
|
||||
index,
|
||||
testcase.base,
|
||||
testcase.size));
|
||||
@ -173,7 +173,7 @@ TEST(CheckedAddressRange, ContainsValue) {
|
||||
for (size_t index = 0; index < arraysize(kTestData); ++index) {
|
||||
const TestData& testcase = kTestData[index];
|
||||
SCOPED_TRACE(base::StringPrintf(
|
||||
"index %" PRIuS ", value 0x%llx", index, testcase.value));
|
||||
"index %" PRIuS ", value 0x%" PRIx64, index, testcase.value));
|
||||
|
||||
EXPECT_EQ(testcase.expectation,
|
||||
parent_range_32.ContainsValue(testcase.value));
|
||||
@ -230,7 +230,7 @@ TEST(CheckedAddressRange, ContainsRange) {
|
||||
for (size_t index = 0; index < arraysize(kTestData); ++index) {
|
||||
const TestData& testcase = kTestData[index];
|
||||
SCOPED_TRACE(base::StringPrintf("index %" PRIuS
|
||||
", base 0x%llx, size 0x%llx",
|
||||
", base 0x%" PRIx64 ", size 0x%" PRIx64,
|
||||
index,
|
||||
testcase.base,
|
||||
testcase.size));
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -25,12 +26,17 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "base/files/scoped_file.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/posix/eintr_wrapper.h"
|
||||
#include "build/build_config.h"
|
||||
#include "util/misc/implicit_cast.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
// Everything in this file is expected to execute between fork() and exec(),
|
||||
// so everything called here must be acceptable in this context. However,
|
||||
// logging code that is not expected to execute under normal circumstances is
|
||||
@ -82,7 +88,7 @@ using ScopedDIR = std::unique_ptr<DIR, ScopedDIRCloser>;
|
||||
bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
|
||||
#if defined(OS_MACOSX)
|
||||
const char kFDDir[] = "/dev/fd";
|
||||
#elif defined(OS_LINUX)
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
const char kFDDir[] = "/proc/self/fd";
|
||||
#endif
|
||||
|
||||
@ -100,10 +106,19 @@ bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dirent entry;
|
||||
dirent* result;
|
||||
int rv;
|
||||
while ((rv = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) {
|
||||
#if defined(OS_LINUX)
|
||||
// readdir_r() is deprecated as of glibc 2.24. See
|
||||
// https://sourceware.org/bugzilla/show_bug.cgi?id=19056 and
|
||||
// https://git.kernel.org/cgit/docs/man-pages/man-pages.git/commit?id=0c52f6d623636a61eacd0f7b7a3bb942793a2a05.
|
||||
const char kReaddirName[] = "readdir";
|
||||
while ((errno = 0, result = readdir(dir)) != nullptr)
|
||||
#else
|
||||
const char kReaddirName[] = "readdir_r";
|
||||
dirent entry;
|
||||
while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr)
|
||||
#endif
|
||||
{
|
||||
const char* entry_name = &(*result->d_name);
|
||||
if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) {
|
||||
continue;
|
||||
@ -127,6 +142,11 @@ bool CloseMultipleNowOrOnExecUsingFDDir(int fd, int preserve_fd) {
|
||||
}
|
||||
}
|
||||
|
||||
if (errno != 0) {
|
||||
PLOG(WARNING) << kReaddirName;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -141,12 +161,68 @@ void CloseMultipleNowOrOnExec(int fd, int preserve_fd) {
|
||||
// system’s file descriptor limit. Check a few values and use the highest as
|
||||
// the limit, because these may be based on the file descriptor limit set by
|
||||
// setrlimit(), and higher-numbered file descriptors may have been opened
|
||||
// prior to the limit being lowered. For Mac OS X, see 10.9.2
|
||||
// Libc-997.90.3/gen/FreeBSD/sysconf.c sysconf() and 10.9.4
|
||||
// xnu-2422.110.17/bsd/kern/kern_descrip.c getdtablesize(), which both return
|
||||
// the current RLIMIT_NOFILE value, not the maximum possible file descriptor.
|
||||
int max_fd = std::max(implicit_cast<int>(sysconf(_SC_OPEN_MAX)), OPEN_MAX);
|
||||
// prior to the limit being lowered. On both macOS and Linux glibc, both
|
||||
// sysconf() and getdtablesize() return the current RLIMIT_NOFILE value, not
|
||||
// the maximum possible file descriptor. For macOS, see 10.11.5
|
||||
// Libc-1082.50.1/gen/FreeBSD/sysconf.c sysconf() and 10.11.6
|
||||
// xnu-3248.60.10/bsd/kern/kern_descrip.c getdtablesize(). For Linux glibc,
|
||||
// see glibc-2.24/sysdeps/posix/sysconf.c __sysconf() and
|
||||
// glibc-2.24/sysdeps/posix/getdtsz.c __getdtablesize(). For Android, see
|
||||
// 7.0.0 bionic/libc/bionic/sysconf.cpp sysconf() and
|
||||
// bionic/libc/bionic/ndk_cruft.cpp getdtablesize().
|
||||
int max_fd = implicit_cast<int>(sysconf(_SC_OPEN_MAX));
|
||||
|
||||
#if !defined(OS_ANDROID)
|
||||
// getdtablesize() was removed effective Android 5.0.0 (API 21). Since it
|
||||
// returns the same thing as the sysconf() above, just skip it. See
|
||||
// https://android.googlesource.com/platform/bionic/+/462abab12b074c62c0999859e65d5a32ebb41951.
|
||||
max_fd = std::max(max_fd, getdtablesize());
|
||||
#endif
|
||||
|
||||
#if !defined(OS_LINUX) || defined(OPEN_MAX)
|
||||
// Linux does not provide OPEN_MAX. See
|
||||
// https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/include/linux/limits.h?id=77293034696e3e0b6c8b8fc1f96be091104b3d2b.
|
||||
max_fd = std::max(max_fd, OPEN_MAX);
|
||||
#endif
|
||||
|
||||
// Consult a sysctl to determine the system-wide limit on the maximum number
|
||||
// of open files per process. Note that it is possible to change this limit
|
||||
// while the system is running, but it’s still a better upper bound than the
|
||||
// current RLIMIT_NOFILE value.
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// See 10.11.6 xnu-3248.60.10/bsd/kern/kern_resource.c maxfilesperproc,
|
||||
// referenced by dosetrlimit().
|
||||
int oid[] = {CTL_KERN, KERN_MAXFILESPERPROC};
|
||||
int maxfilesperproc;
|
||||
size_t maxfilesperproc_size = sizeof(maxfilesperproc);
|
||||
if (sysctl(oid,
|
||||
arraysize(oid),
|
||||
&maxfilesperproc,
|
||||
&maxfilesperproc_size,
|
||||
nullptr,
|
||||
0) == 0) {
|
||||
max_fd = std::max(max_fd, maxfilesperproc);
|
||||
} else {
|
||||
PLOG(WARNING) << "sysctl";
|
||||
}
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// See linux-4.4.27/fs/file.c sysctl_nr_open, referenced by kernel/sys.c
|
||||
// do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is
|
||||
// not considered an error, because /proc may not be available or usable.
|
||||
{
|
||||
base::ScopedFILE nr_open_file(fopen("/proc/sys/fs/nr_open", "r"));
|
||||
if (nr_open_file.get() != nullptr) {
|
||||
int nr_open;
|
||||
if (fscanf(nr_open_file.get(), "%d\n", &nr_open) == 1 &&
|
||||
feof(nr_open_file.get())) {
|
||||
max_fd = std::max(max_fd, nr_open);
|
||||
} else {
|
||||
LOG(WARNING) << "/proc/sys/fs/nr_open format error";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int entry_fd = fd; entry_fd < max_fd; ++entry_fd) {
|
||||
if (entry_fd != preserve_fd) {
|
||||
|
@ -71,7 +71,7 @@ void DropPrivileges() {
|
||||
CHECK_EQ(setegid(egid), -1);
|
||||
}
|
||||
}
|
||||
#elif defined(OS_LINUX)
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
PCHECK(setresgid(gid, gid, gid) == 0) << "setresgid";
|
||||
PCHECK(setresuid(uid, uid, uid) == 0) << "setresuid";
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#ifndef CRASHPAD_UTIL_POSIX_PROCESS_INFO_H_
|
||||
#define CRASHPAD_UTIL_POSIX_PROCESS_INFO_H_
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
@ -30,6 +29,7 @@
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
#include <mach/mach.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
namespace crashpad {
|
||||
|
@ -15,12 +15,14 @@
|
||||
#include "util/posix/process_info.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/scoped_file.h"
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "test/errors.h"
|
||||
@ -98,6 +100,34 @@ void TestSelfProcess(const ProcessInfo& process_info) {
|
||||
#if defined(OS_MACOSX)
|
||||
int expect_argc = *_NSGetArgc();
|
||||
char** expect_argv = *_NSGetArgv();
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
std::vector<std::string> expect_arg_vector;
|
||||
{
|
||||
base::ScopedFILE cmdline(fopen("/proc/self/cmdline", "r"));
|
||||
ASSERT_NE(nullptr, cmdline.get()) << ErrnoMessage("fopen");
|
||||
|
||||
int expect_arg_char;
|
||||
std::string expect_arg_string;
|
||||
while ((expect_arg_char = fgetc(cmdline.get())) != EOF) {
|
||||
if (expect_arg_char != '\0') {
|
||||
expect_arg_string.append(1, expect_arg_char);
|
||||
} else {
|
||||
expect_arg_vector.push_back(expect_arg_string);
|
||||
expect_arg_string.clear();
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, ferror(cmdline.get())) << ErrnoMessage("fgetc");
|
||||
ASSERT_TRUE(expect_arg_string.empty());
|
||||
}
|
||||
|
||||
std::vector<const char*> expect_argv_storage;
|
||||
for (const std::string& expect_arg_string : expect_arg_vector) {
|
||||
expect_argv_storage.push_back(expect_arg_string.c_str());
|
||||
}
|
||||
|
||||
int expect_argc = expect_argv_storage.size();
|
||||
const char* const* expect_argv =
|
||||
!expect_argv_storage.empty() ? &expect_argv_storage[0] : nullptr;
|
||||
#else
|
||||
#error Obtain expect_argc and expect_argv correctly on your system.
|
||||
#endif
|
||||
|
@ -14,9 +14,9 @@
|
||||
|
||||
#include "util/posix/symbolic_constants_posix.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
@ -64,7 +64,7 @@ const char* kSignalNames[] = {
|
||||
"INFO",
|
||||
"USR1",
|
||||
"USR2",
|
||||
#elif defined(OS_LINUX)
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// sed -Ene 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/ "\1",/p'
|
||||
// /usr/include/asm-generic/signal.h
|
||||
// and fix up by removing SIGIOT, SIGLOST, SIGUNUSED, and SIGRTMIN.
|
||||
@ -101,7 +101,7 @@ const char* kSignalNames[] = {
|
||||
"SYS",
|
||||
#endif
|
||||
};
|
||||
#if defined(OS_LINUX)
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// NSIG is 64 to account for real-time signals.
|
||||
static_assert(arraysize(kSignalNames) == 32, "kSignalNames length");
|
||||
#else
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#include "util/posix/symbolic_constants_posix.h"
|
||||
|
||||
#include <sys/signal.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
@ -65,7 +65,7 @@ const struct {
|
||||
#if defined(OS_MACOSX)
|
||||
{SIGEMT, "SIGEMT", "EMT"},
|
||||
{SIGINFO, "SIGINFO", "INFO"},
|
||||
#elif defined(OS_LINUX)
|
||||
#elif defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
{SIGPWR, "SIGPWR", "PWR"},
|
||||
{SIGSTKFLT, "SIGSTKFLT", "STKFLT"},
|
||||
#endif
|
||||
@ -120,7 +120,7 @@ TEST(SymbolicConstantsPOSIX, SignalToString) {
|
||||
kSignalTestData[index].short_name);
|
||||
}
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
#if defined(OS_LINUX) || defined(OS_ANDROID)
|
||||
// NSIG is 64 to account for real-time signals.
|
||||
const int kSignalCount = 32;
|
||||
#else
|
||||
|
@ -103,6 +103,7 @@ struct StringToUnsignedIntTraits
|
||||
: public StringToUnsignedIntegerTraits<unsigned int, unsigned long> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
if (str[0] == '-') {
|
||||
*end = const_cast<char*>(str);
|
||||
return 0;
|
||||
}
|
||||
return strtoul(str, end, base);
|
||||
@ -113,6 +114,7 @@ struct StringToUnsignedInt64Traits
|
||||
: public StringToUnsignedIntegerTraits<uint64_t, uint64_t> {
|
||||
static LongType Convert(const char* str, char** end, int base) {
|
||||
if (str[0] == '-') {
|
||||
*end = const_cast<char*>(str);
|
||||
return 0;
|
||||
}
|
||||
return strtoull(str, end, base);
|
||||
|
@ -46,14 +46,14 @@ class ThreadLogMessagesMaster {
|
||||
}
|
||||
|
||||
~ThreadLogMessagesMaster() {
|
||||
DCHECK_EQ(logging::GetLogMessageHandler(), LogMessageHandler);
|
||||
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
|
||||
logging::SetLogMessageHandler(nullptr);
|
||||
|
||||
tls_.Free();
|
||||
}
|
||||
|
||||
void SetThreadMessageList(std::vector<std::string>* message_list) {
|
||||
DCHECK_EQ(logging::GetLogMessageHandler(), LogMessageHandler);
|
||||
DCHECK_EQ(logging::GetLogMessageHandler(), &LogMessageHandler);
|
||||
DCHECK_NE(tls_.Get() != nullptr, message_list != nullptr);
|
||||
tls_.Set(message_list);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user