Merge master c332e7ffdab6 into doc

This commit is contained in:
Mark Mentovai 2017-07-29 17:13:35 -04:00
commit 926971a33b
187 changed files with 5244 additions and 1084 deletions

2
DEPS
View File

@ -38,7 +38,7 @@ deps = {
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'723e840a2f100a525f7feaad2e93df31d701780a',
'ee67585e3115982282b86e210939ead1791e696d',
'crashpad/third_party/zlib/zlib':
Var('chromium_git') + '/chromium/src/third_party/zlib@' +
'13dc246a58e4b72104d35f9b1809af95221ebda7',

View File

@ -42,29 +42,30 @@ namespace crashpad {
namespace {
const char kWriteDirectory[] = "new";
const char kUploadPendingDirectory[] = "pending";
const char kCompletedDirectory[] = "completed";
constexpr char kWriteDirectory[] = "new";
constexpr char kUploadPendingDirectory[] = "pending";
constexpr char kCompletedDirectory[] = "completed";
const char kSettings[] = "settings.dat";
constexpr char kSettings[] = "settings.dat";
const char* const kReportDirectories[] = {
constexpr const char* kReportDirectories[] = {
kWriteDirectory,
kUploadPendingDirectory,
kCompletedDirectory,
};
const char kCrashReportFileExtension[] = "dmp";
constexpr char kCrashReportFileExtension[] = "dmp";
const char kXattrUUID[] = "uuid";
const char kXattrCollectorID[] = "id";
const char kXattrCreationTime[] = "creation_time";
const char kXattrIsUploaded[] = "uploaded";
const char kXattrLastUploadTime[] = "last_upload_time";
const char kXattrUploadAttemptCount[] = "upload_count";
const char kXattrIsUploadExplicitlyRequested[] = "upload_explicitly_requested";
constexpr char kXattrUUID[] = "uuid";
constexpr char kXattrCollectorID[] = "id";
constexpr char kXattrCreationTime[] = "creation_time";
constexpr char kXattrIsUploaded[] = "uploaded";
constexpr char kXattrLastUploadTime[] = "last_upload_time";
constexpr char kXattrUploadAttemptCount[] = "upload_count";
constexpr char kXattrIsUploadExplicitlyRequested[] =
"upload_explicitly_requested";
const char kXattrDatabaseInitialized[] = "initialized";
constexpr char kXattrDatabaseInitialized[] = "initialized";
// Ensures that the node at |path| is a directory. If the |path| refers to a
// file, rather than a directory, returns false. Otherwise, returns true,

View File

@ -51,7 +51,7 @@ class CrashReportDatabaseTest : public testing::Test {
CrashReportDatabase::NewReport* new_report = nullptr;
ASSERT_EQ(db_->PrepareNewCrashReport(&new_report),
CrashReportDatabase::kNoError);
const char kTest[] = "test";
static constexpr char kTest[] = "test";
ASSERT_TRUE(LoggingWriteFile(new_report->handle, kTest, sizeof(kTest)));
UUID uuid;

View File

@ -36,15 +36,15 @@ namespace crashpad {
namespace {
const wchar_t kReportsDirectory[] = L"reports";
const wchar_t kMetadataFileName[] = L"metadata";
constexpr wchar_t kReportsDirectory[] = L"reports";
constexpr wchar_t kMetadataFileName[] = L"metadata";
const wchar_t kSettings[] = L"settings.dat";
constexpr wchar_t kSettings[] = L"settings.dat";
const wchar_t kCrashReportFileExtension[] = L"dmp";
constexpr wchar_t kCrashReportFileExtension[] = L"dmp";
const uint32_t kMetadataFileHeaderMagic = 'CPAD';
const uint32_t kMetadataFileVersion = 1;
constexpr uint32_t kMetadataFileHeaderMagic = 'CPAD';
constexpr uint32_t kMetadataFileVersion = 1;
using OperationStatus = CrashReportDatabase::OperationStatus;

View File

@ -284,8 +284,8 @@ class HandlerStarter final : public NotifyServer::DefaultInterface {
if (restart) {
// If the handler was ever started before, dont restart it too quickly.
const uint64_t kNanosecondsPerSecond = 1E9;
const uint64_t kMinimumStartInterval = 1 * kNanosecondsPerSecond;
constexpr uint64_t kNanosecondsPerSecond = 1E9;
constexpr uint64_t kMinimumStartInterval = 1 * kNanosecondsPerSecond;
const uint64_t earliest_next_start_time =
handler_restarter->last_start_time_ + kMinimumStartInterval;

View File

@ -164,7 +164,7 @@ LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) {
SetEvent(g_signal_exception);
// Time to wait for the handler to create a dump.
const DWORD kMillisecondsUntilTerminate = 60 * 1000;
constexpr DWORD kMillisecondsUntilTerminate = 60 * 1000;
// Sleep for a while to allow it to process us. Eventually, we terminate
// ourselves in case the crash server is gone, so that we don't leave zombies
@ -753,7 +753,7 @@ void CrashpadClient::DumpWithoutCrash(const CONTEXT& context) {
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx have
// some of the top nibble set, so we make sure to pick a value that doesn't,
// so as to be unlikely to conflict.
const uint32_t kSimulatedExceptionCode = 0x517a7ed;
constexpr uint32_t kSimulatedExceptionCode = 0x517a7ed;
EXCEPTION_RECORD record = {};
record.ExceptionCode = kSimulatedExceptionCode;
#if defined(ARCH_CPU_64_BITS)
@ -829,7 +829,7 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process,
}
}
const size_t kInjectBufferSize = 4 * 1024;
constexpr size_t kInjectBufferSize = 4 * 1024;
WinVMAddress inject_memory =
FromPointerCast<WinVMAddress>(VirtualAllocEx(process,
nullptr,
@ -1001,7 +1001,10 @@ bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process,
// letting this cause an exception, even when the target is stuck in the
// loader lock.
HANDLE injected_thread;
const size_t kStackSize = 0x4000; // This is what DebugBreakProcess() uses.
// This is what DebugBreakProcess() uses.
constexpr size_t kStackSize = 0x4000;
NTSTATUS status = NtCreateThreadEx(&injected_thread,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
nullptr,

View File

@ -28,7 +28,7 @@
namespace {
static const uint32_t kCrashpadInfoVersion = 1;
constexpr uint32_t kCrashpadInfoVersion = 1;
} // namespace

View File

@ -147,7 +147,7 @@ class StaticCondition final : public PruneCondition {
};
TEST(PruneCrashReports, BinaryCondition) {
const struct {
static constexpr struct {
const char* name;
BinaryPruneCondition::Operator op;
bool lhs_value;

View File

@ -41,7 +41,7 @@ class SettingsTest : public testing::Test {
FilePermissions::kWorldReadable));
ASSERT_TRUE(handle.is_valid());
const char kBuf[] = "test bad file";
static constexpr char kBuf[] = "test bad file";
ASSERT_TRUE(LoggingWriteFile(handle.get(), kBuf, sizeof(kBuf)));
handle.reset();
}

View File

@ -121,8 +121,8 @@ TEST(SimpleStringDictionary, Iterator) {
char key[SimpleStringDictionary::key_size];
char value[SimpleStringDictionary::value_size];
const int kDictionaryCapacity = SimpleStringDictionary::num_entries;
const int kPartitionIndex = kDictionaryCapacity - 5;
constexpr int kDictionaryCapacity = SimpleStringDictionary::num_entries;
constexpr int kPartitionIndex = kDictionaryCapacity - 5;
// We assume at least this size in the tests below
ASSERT_GE(kDictionaryCapacity, 64);

View File

@ -196,7 +196,7 @@ void SimulateCrash(const NativeCPUContext& cpu_context) {
// Look up the handler for EXC_CRASH exceptions in the same way that the
// kernel would: try a thread handler, then a task handler, and finally a host
// handler. 10.9.5 xnu-2422.115.4/osfmk/kern/exception.c exception_triage().
const ExceptionPorts::TargetType kTargetTypes[] = {
static constexpr ExceptionPorts::TargetType kTargetTypes[] = {
ExceptionPorts::kTargetTypeThread,
ExceptionPorts::kTargetTypeTask,

View File

@ -307,14 +307,14 @@ class TestSimulateCrashMac final : public MachMultiprocess,
};
TEST(SimulateCrash, SimulateCrash) {
const TestSimulateCrashMac::ExceptionPortsTarget kTargets[] = {
static constexpr TestSimulateCrashMac::ExceptionPortsTarget kTargets[] = {
TestSimulateCrashMac::kExceptionPortsTargetNone,
TestSimulateCrashMac::kExceptionPortsTargetTask,
TestSimulateCrashMac::kExceptionPortsTargetThread,
TestSimulateCrashMac::kExceptionPortsTargetBoth,
};
const exception_behavior_t kBehaviors[] = {
static constexpr exception_behavior_t kBehaviors[] = {
EXCEPTION_DEFAULT,
EXCEPTION_STATE,
EXCEPTION_STATE_IDENTITY,
@ -323,7 +323,7 @@ TEST(SimulateCrash, SimulateCrash) {
EXCEPTION_STATE_IDENTITY | kMachExceptionCodes,
};
const thread_state_flavor_t kFlavors[] = {
static constexpr thread_state_flavor_t kFlavors[] = {
#if defined(ARCH_CPU_X86_FAMILY)
x86_THREAD_STATE,
x86_FLOAT_STATE,

38
compat/android/elf.h Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2017 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.
#ifndef CRASHPAD_COMPAT_ANDROID_ELF_H_
#define CRASHPAD_COMPAT_ANDROID_ELF_H_
#include_next <elf.h>
#if !defined(ELF32_ST_VISIBILITY)
#define ELF32_ST_VISIBILITY(other) ((other) & 0x3)
#endif
#if !defined(ELF64_ST_VISIBILITY)
#define ELF64_ST_VISIBILITY(other) ELF32_ST_VISIBILITY(other)
#endif
// Android 5.0.0 (API 21) NDK
#if !defined(STT_COMMON)
#define STT_COMMON 5
#endif
#if !defined(STT_TLS)
#define STT_TLS 6
#endif
#endif // CRASHPAD_COMPAT_ANDROID_ELF_H_

30
compat/android/sched.h Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2017 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.
#ifndef CRASHPAD_COMPAT_ANDROID_SCHED_H_
#define CRASHPAD_COMPAT_ANDROID_SCHED_H_
#include_next <sched.h>
// Android 5.0.0 (API 21) NDK
#if !defined(SCHED_BATCH)
#define SCHED_BATCH 3
#endif
#if !defined(SCHED_IDLE)
#define SCHED_IDLE 5
#endif
#endif // CRASHPAD_COMPAT_ANDROID_SCHED_H_

View File

@ -1,4 +1,4 @@
// Copyright 2014 The Crashpad Authors. All rights reserved.
// Copyright 2017 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.
@ -12,12 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "util/net/http_headers.h"
#ifndef CRASHPAD_COMPAT_ANDROID_SYS_SYSCALL_H_
#define CRASHPAD_COMPAT_ANDROID_SYS_SYSCALL_H_
namespace crashpad {
#include_next <sys/syscall.h>
const char kContentType[] = "Content-Type";
const char kContentLength[] = "Content-Length";
const char kContentEncoding[] = "Content-Encoding";
// Android 5.0.0 (API 21) NDK
#if !defined(SYS_gettid)
#define SYS_gettid __NR_gettid
#endif
} // namespace crashpad
#endif // CRASHPAD_COMPAT_ANDROID_SYS_SYSCALL_H_

View File

@ -94,6 +94,16 @@
],
},
}],
['OS=="linux"', {
'include_dirs': [
'linux',
],
'direct_dependent_settings': {
'include_dirs': [
'linux',
],
},
}],
],
},
],

27
compat/linux/sys/ptrace.h Normal file
View File

@ -0,0 +1,27 @@
// Copyright 2017 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.
#ifndef CRASHPAD_COMPAT_LINUX_SYS_PTRACE_H_
#define CRASHPAD_COMPAT_LINUX_SYS_PTRACE_H_
#include_next <sys/ptrace.h>
#include <sys/cdefs.h>
#if defined(__GLIBC__) && defined(__x86_64__)
static constexpr __ptrace_request PTRACE_GET_THREAD_AREA =
static_cast<__ptrace_request>(25);
#endif // __GLIBC__ && __x86_64__
#endif // CRASHPAD_COMPAT_LINUX_SYS_PTRACE_H_

View File

@ -119,7 +119,7 @@ Kit)](https://developer.android.com/ndk/) runs on.
If its not already present on your system, [download the NDK package for your
system](https://developer.android.com/ndk/downloads/) and expand it to a
suitable location. These instructions assume that its been expanded to
`~/android-ndk-r14`.
`~/android-ndk-r15b`.
To build Crashpad, portions of the NDK must be reassembled into a [standalone
toolchain](https://developer.android.com/ndk/guides/standalone_toolchain.html).
@ -133,8 +133,8 @@ desired. To build a standalone toolchain targeting 64-bit ARM and API level 21
```
$ cd ~
$ python android-ndk-r14/build/tools/make_standalone_toolchain.py \
--arch=arm64 --api=21 --install-dir=android-ndk-r14_arm64_api21
$ python android-ndk-r15b/build/tools/make_standalone_toolchain.py \
--arch=arm64 --api=21 --install-dir=android-ndk-r15b_arm64_api21
```
Note that Chrome uses Android API level 21 for 64-bit platforms and 16 for
@ -152,7 +152,7 @@ operation.
```
$ cd ~/crashpad/crashpad
$ python build/gyp_crashpad_android.py \
--ndk ~/android-ndk-r14_arm64_api21 \
--ndk ~/android-ndk-r15b_arm64_api21 \
--generator-output out/android_arm64_api21
```

View File

@ -268,7 +268,7 @@ void CrashReportUploadThread::ProcessPendingReport(
// If the most recent upload attempt occurred within the past hour,
// dont attempt to upload the new report. If it happened longer ago,
// attempt to upload the report.
const int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour
constexpr int kUploadAttemptIntervalSeconds = 60 * 60; // 1 hour
if (now - last_upload_attempt_time < kUploadAttemptIntervalSeconds) {
database_->SkipReportUpload(
report.uuid, Metrics::CrashSkippedReason::kUploadThrottled);
@ -280,7 +280,7 @@ void CrashReportUploadThread::ProcessPendingReport(
// upload attempt time is bogus, and attempt to upload the report. If
// the most recent upload time is in the future but within one day,
// accept it and dont attempt to upload the report.
const int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day
constexpr int kBackwardsClockTolerance = 60 * 60 * 24; // 1 day
if (last_upload_attempt_time - now < kBackwardsClockTolerance) {
database_->SkipReportUpload(
report.uuid, Metrics::CrashSkippedReason::kUnexpectedTime);
@ -361,7 +361,7 @@ CrashReportUploadThread::UploadResult CrashReportUploadThread::UploadReport(
HTTPMultipartBuilder http_multipart_builder;
http_multipart_builder.SetGzipEnabled(upload_gzip_);
const char kMinidumpKey[] = "upload_file_minidump";
static constexpr char kMinidumpKey[] = "upload_file_minidump";
for (const auto& kv : parameters) {
if (kv.first == kMinidumpKey) {

View File

@ -115,7 +115,7 @@ void CrashWithExtendedHandler::ValidateGeneratedDump() {
ASSERT_TRUE(reader.ReadExactly(data.data(), data.size()));
static const char kExpectedData[] = "Injected extension stream!";
static constexpr char kExpectedData[] = "Injected extension stream!";
EXPECT_EQ(memcmp(kExpectedData, data.data(), sizeof(kExpectedData)), 0);
}
}

View File

@ -39,7 +39,7 @@ class TestUserStreamDataSource : public crashpad::UserStreamDataSource {
std::unique_ptr<crashpad::MinidumpUserExtensionStreamDataSource>
TestUserStreamDataSource::ProduceStreamData(
crashpad::ProcessSnapshot* process_snapshot) {
static const char kTestData[] = "Injected extension stream!";
static constexpr char kTestData[] = "Injected extension stream!";
return base::WrapUnique(new crashpad::test::BufferExtensionStreamDataSource(
0xCAFEBABE, kTestData, sizeof(kTestData)));

View File

@ -436,7 +436,7 @@ int HandlerMain(int argc,
kOptionVersion = -3,
};
const option long_options[] = {
static constexpr option long_options[] = {
{"annotation", required_argument, nullptr, kOptionAnnotation},
{"database", required_argument, nullptr, kOptionDatabase},
#if defined(OS_MACOSX)
@ -714,8 +714,8 @@ int HandlerMain(int argc,
base::GlobalHistogramAllocator* histogram_allocator = nullptr;
if (!options.metrics_dir.empty()) {
static const char kMetricsName[] = "CrashpadMetrics";
const size_t kMetricsFileSize = 1 << 20;
static constexpr char kMetricsName[] = "CrashpadMetrics";
constexpr size_t kMetricsFileSize = 1 << 20;
if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir(
options.metrics_dir, kMetricsFileSize, 0, kMetricsName)) {
histogram_allocator = base::GlobalHistogramAllocator::Get();

View File

@ -14,7 +14,9 @@
#include "handler/mac/file_limit_annotation.h"
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/types.h>
@ -26,6 +28,9 @@
#include "base/strings/stringprintf.h"
#include "client/crashpad_info.h"
#include "client/simple_string_dictionary.h"
#include "util/posix/scoped_dir.h"
namespace crashpad {
namespace {
@ -44,6 +49,38 @@ std::string FormatFromSysctl(int rv, const int* value, const size_t* size) {
return base::StringPrintf("%d", *value);
}
// Counts the number of open file descriptors in the process and returns it as a
// string. This /dev/fd and the value returned will include the open file
// descriptor for that directory. If opendir() fails, the returned string will
// be "E" followed by the error number. If readdir_r() fails, it will be "R"
// followed by the error number.
std::string CountOpenFileDescriptors() {
DIR* dir = opendir("/dev/fd");
if (!dir) {
return base::StringPrintf("E%d", errno);
}
ScopedDIR dir_owner(dir);
dirent entry;
dirent* result;
int count = 0;
while ((errno = readdir_r(dir, &entry, &result)) == 0 && result != nullptr) {
const char* entry_name = &(*result->d_name);
if (strcmp(entry_name, ".") == 0 || strcmp(entry_name, "..") == 0) {
continue;
}
++count;
}
if (errno != 0) {
return base::StringPrintf("R%d", errno);
}
return base::StringPrintf("%d", count);
}
// Returns a string for |limit|, or "inf" if |limit| is RLIM_INFINITY.
std::string StringForRLim(rlim_t limit) {
if (limit == RLIM_INFINITY) {
@ -55,8 +92,6 @@ std::string StringForRLim(rlim_t limit) {
} // namespace
namespace crashpad {
void RecordFileLimitAnnotation() {
CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
SimpleStringDictionary* simple_annotations =
@ -76,6 +111,8 @@ void RecordFileLimitAnnotation() {
std::string max_files = FormatFromSysctl(
sysctl(mib, arraysize(mib), &value, &size, nullptr, 0), &value, &size);
std::string open_files = CountOpenFileDescriptors();
rlimit limit;
std::string nofile;
if (getrlimit(RLIMIT_NOFILE, &limit) != 0) {
@ -85,8 +122,11 @@ void RecordFileLimitAnnotation() {
StringForRLim(limit.rlim_cur) + "," + StringForRLim(limit.rlim_max);
}
std::string annotation = base::StringPrintf(
"%s,%s,%s", num_files.c_str(), max_files.c_str(), nofile.c_str());
std::string annotation = base::StringPrintf("%s,%s,%s,%s",
num_files.c_str(),
max_files.c_str(),
open_files.c_str(),
nofile.c_str());
simple_annotations->SetKeyValue("file-limits", annotation.c_str());
}

View File

@ -63,20 +63,20 @@ void AllocateMemoryOfVariousProtections() {
const size_t kPageSize = system_info.dwPageSize;
const uint32_t kPageTypes[] = {
PAGE_NOACCESS,
PAGE_READONLY,
PAGE_READWRITE,
PAGE_EXECUTE,
PAGE_EXECUTE_READ,
PAGE_EXECUTE_READWRITE,
static constexpr uint32_t kPageTypes[] = {
PAGE_NOACCESS,
PAGE_READONLY,
PAGE_READWRITE,
PAGE_EXECUTE,
PAGE_EXECUTE_READ,
PAGE_EXECUTE_READWRITE,
// PAGE_NOACCESS is invalid with PAGE_GUARD.
PAGE_READONLY | PAGE_GUARD,
PAGE_READWRITE | PAGE_GUARD,
PAGE_EXECUTE | PAGE_GUARD,
PAGE_EXECUTE_READ | PAGE_GUARD,
PAGE_EXECUTE_READWRITE | PAGE_GUARD,
// PAGE_NOACCESS is invalid with PAGE_GUARD.
PAGE_READONLY | PAGE_GUARD,
PAGE_READWRITE | PAGE_GUARD,
PAGE_EXECUTE | PAGE_GUARD,
PAGE_EXECUTE_READ | PAGE_GUARD,
PAGE_EXECUTE_READWRITE | PAGE_GUARD,
};
// All of these allocations are leaked, we want to view them in windbg via
@ -142,7 +142,7 @@ void SomeCrashyFunction() {
void AllocateExtraMemoryToBeSaved(
crashpad::SimpleAddressRangeBag* extra_ranges) {
const size_t kNumInts = 2000;
constexpr size_t kNumInts = 2000;
int* extra_memory = new int[kNumInts];
g_extra_memory_pointer = extra_memory;
for (int i = 0; i < kNumInts; ++i)
@ -154,7 +154,7 @@ void AllocateExtraMemoryToBeSaved(
void AllocateExtraUnsavedMemory(crashpad::SimpleAddressRangeBag* extra_ranges) {
// Allocate some extra memory, and then Insert() but also Remove() it so we
// can confirm it doesn't get saved.
const size_t kNumInts = 2000;
constexpr size_t kNumInts = 2000;
int* extra_memory = new int[kNumInts];
g_extra_memory_not_saved = extra_memory;
for (int i = 0; i < kNumInts; ++i)
@ -211,7 +211,7 @@ int CrashyMain(int argc, wchar_t* argv[]) {
FreeLibrary(wmerror);
// Make sure data pointed to by the stack is captured.
const int kDataSize = 512;
constexpr int kDataSize = 512;
int* pointed_to_data = new int[kDataSize];
for (int i = 0; i < kDataSize; ++i)
pointed_to_data[i] = i | ((i % 2 == 0) ? 0x80000000 : 0);

View File

@ -33,14 +33,10 @@ verifiers {
try_job {
buckets {
name: "master.client.crashpad"
builders { name: "crashpad_try_mac_dbg" }
builders { name: "crashpad_try_mac_rel" }
builders { name: "crashpad_try_win_x64_dbg" }
builders { name: "crashpad_try_win_x64_rel" }
builders { name: "crashpad_try_win_x86_dbg" }
builders { name: "crashpad_try_win_x86_rel" }
builders { name: "crashpad_try_win_x86_wow64_dbg" }
builders { name: "crashpad_try_win_x86_wow64_rel" }
builders { name: "mac_dbg" }
builders { name: "mac_rel" }
builders { name: "win_x64_dbg" }
builders { name: "win_x64_rel" }
}
}
}

View File

@ -52,7 +52,7 @@ TEST(MinidumpContextWriter, MinidumpContextX86Writer) {
SCOPED_TRACE("nonzero");
string_file.Reset();
const uint32_t kSeed = 0x8086;
constexpr uint32_t kSeed = 0x8086;
MinidumpContextX86Writer context_writer;
InitializeMinidumpContextX86(context_writer.context(), kSeed);
@ -92,7 +92,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
SCOPED_TRACE("nonzero");
string_file.Reset();
const uint32_t kSeed = 0x808664;
constexpr uint32_t kSeed = 0x808664;
MinidumpContextAMD64Writer context_writer;
InitializeMinidumpContextAMD64(context_writer.context(), kSeed);
@ -109,7 +109,7 @@ TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) {
}
TEST(MinidumpContextWriter, CreateFromSnapshot_X86) {
const uint32_t kSeed = 32;
constexpr uint32_t kSeed = 32;
CPUContextX86 context_snapshot_x86;
CPUContext context_snapshot;
@ -131,7 +131,7 @@ TEST(MinidumpContextWriter, CreateFromSnapshot_X86) {
}
TEST(MinidumpContextWriter, CreateFromSnapshot_AMD64) {
const uint32_t kSeed = 64;
constexpr uint32_t kSeed = 64;
CPUContextX86_64 context_snapshot_x86_64;
CPUContext context_snapshot;

View File

@ -130,10 +130,10 @@ TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) {
auto crashpad_info_writer =
base::WrapUnique(new MinidumpCrashpadInfoWriter());
const char kKey[] =
static constexpr char kKey[] =
"a thing that provides a means of gaining access to or understanding "
"something";
const char kValue[] =
static constexpr char kValue[] =
"the numerical amount denoted by an algebraic term; a magnitude, "
"quantity, or number";
auto simple_string_dictionary_writer =
@ -174,7 +174,7 @@ TEST(MinidumpCrashpadInfoWriter, SimpleAnnotations) {
}
TEST(MinidumpCrashpadInfoWriter, CrashpadModuleList) {
const uint32_t kMinidumpModuleListIndex = 3;
constexpr uint32_t kMinidumpModuleListIndex = 3;
MinidumpFileWriter minidump_file_writer;
auto crashpad_info_writer =
@ -230,9 +230,9 @@ TEST(MinidumpCrashpadInfoWriter, InitializeFromSnapshot) {
ASSERT_TRUE(
client_id.InitializeFromString("fedcba98-7654-3210-0123-456789abcdef"));
const char kKey[] = "version";
const char kValue[] = "40.0.2214.111";
const char kEntry[] = "This is a simple annotation in a list.";
static constexpr char kKey[] = "version";
static constexpr char kValue[] = "40.0.2214.111";
static constexpr char kEntry[] = "This is a simple annotation in a list.";
// Test with a useless module, one that doesnt carry anything that would
// require MinidumpCrashpadInfo or any child object.

View File

@ -64,7 +64,7 @@ void MinidumpExceptionWriter::SetExceptionInformation(
DCHECK_EQ(state(), kStateMutable);
const size_t parameters = exception_information.size();
const size_t kMaxParameters =
constexpr size_t kMaxParameters =
ARRAYSIZE_UNSAFE(exception_.ExceptionRecord.ExceptionInformation);
CHECK_LE(parameters, kMaxParameters);

View File

@ -39,12 +39,12 @@ namespace {
// This returns the MINIDUMP_EXCEPTION_STREAM stream in |exception_stream|.
void GetExceptionStream(const std::string& file_contents,
const MINIDUMP_EXCEPTION_STREAM** exception_stream) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kExceptionStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kExceptionStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kContextOffset =
constexpr size_t kContextOffset =
kExceptionStreamOffset + sizeof(MINIDUMP_EXCEPTION_STREAM);
const size_t kFileSize = kContextOffset + sizeof(MinidumpContextX86);
constexpr size_t kFileSize = kContextOffset + sizeof(MinidumpContextX86);
ASSERT_EQ(kFileSize, file_contents.size());
const MINIDUMP_DIRECTORY* directory;
@ -96,7 +96,7 @@ TEST(MinidumpExceptionWriter, Minimal) {
MinidumpFileWriter minidump_file_writer;
auto exception_writer = base::WrapUnique(new MinidumpExceptionWriter());
const uint32_t kSeed = 100;
constexpr uint32_t kSeed = 100;
auto context_x86_writer = base::WrapUnique(new MinidumpContextX86Writer());
InitializeMinidumpContextX86(context_x86_writer->context(), kSeed);
@ -128,15 +128,15 @@ TEST(MinidumpExceptionWriter, Standard) {
MinidumpFileWriter minidump_file_writer;
auto exception_writer = base::WrapUnique(new MinidumpExceptionWriter());
const uint32_t kSeed = 200;
const uint32_t kThreadID = 1;
const uint32_t kExceptionCode = 2;
const uint32_t kExceptionFlags = 3;
const uint32_t kExceptionRecord = 4;
const uint32_t kExceptionAddress = 5;
const uint64_t kExceptionInformation0 = 6;
const uint64_t kExceptionInformation1 = 7;
const uint64_t kExceptionInformation2 = 7;
constexpr uint32_t kSeed = 200;
constexpr uint32_t kThreadID = 1;
constexpr uint32_t kExceptionCode = 2;
constexpr uint32_t kExceptionFlags = 3;
constexpr uint32_t kExceptionRecord = 4;
constexpr uint32_t kExceptionAddress = 5;
constexpr uint64_t kExceptionInformation0 = 6;
constexpr uint64_t kExceptionInformation1 = 7;
constexpr uint64_t kExceptionInformation2 = 7;
auto context_x86_writer = base::WrapUnique(new MinidumpContextX86Writer());
InitializeMinidumpContextX86(context_x86_writer->context(), kSeed);
@ -212,8 +212,8 @@ TEST(MinidumpExceptionWriter, InitializeFromSnapshot) {
expect_exception.ExceptionRecord.ExceptionInformation[index] =
exception_codes[index];
}
const uint64_t kThreadID = 0xaaaaaaaaaaaaaaaa;
const uint32_t kSeed = 65;
constexpr uint64_t kThreadID = 0xaaaaaaaaaaaaaaaa;
constexpr uint32_t kSeed = 65;
TestExceptionSnapshot exception_snapshot;
exception_snapshot.SetThreadID(kThreadID);

View File

@ -16,7 +16,7 @@
namespace crashpad {
const uint32_t MinidumpModuleCrashpadInfo::kVersion;
const uint32_t MinidumpCrashpadInfo::kVersion;
constexpr uint32_t MinidumpModuleCrashpadInfo::kVersion;
constexpr uint32_t MinidumpCrashpadInfo::kVersion;
} // namespace crashpad

View File

@ -290,7 +290,7 @@ struct ALIGNAS(4) PACKED MinidumpModuleCrashpadInfo {
//! \brief The structures currently-defined version number.
//!
//! \sa version
static const uint32_t kVersion = 1;
static constexpr uint32_t kVersion = 1;
//! \brief The structures version number.
//!
@ -387,7 +387,7 @@ struct ALIGNAS(4) PACKED MinidumpCrashpadInfo {
//! \brief The structures currently-defined version number.
//!
//! \sa version
static const uint32_t kVersion = 1;
static constexpr uint32_t kVersion = 1;
//! \brief The structures version number.
//!

View File

@ -92,12 +92,13 @@ class TestStream final : public internal::MinidumpStreamWriter {
TEST(MinidumpFileWriter, OneStream) {
MinidumpFileWriter minidump_file;
const time_t kTimestamp = 0x155d2fb8;
constexpr time_t kTimestamp = 0x155d2fb8;
minidump_file.SetTimestamp(kTimestamp);
const size_t kStreamSize = 5;
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStreamValue = 0x5a;
constexpr size_t kStreamSize = 5;
constexpr MinidumpStreamType kStreamType =
static_cast<MinidumpStreamType>(0x4d);
constexpr uint8_t kStreamValue = 0x5a;
auto stream =
base::WrapUnique(new TestStream(kStreamType, kStreamSize, kStreamValue));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream)));
@ -105,9 +106,10 @@ TEST(MinidumpFileWriter, OneStream) {
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kFileSize = kStreamOffset + kStreamSize;
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
constexpr size_t kFileSize = kStreamOffset + kStreamSize;
ASSERT_EQ(string_file.string().size(), kFileSize);
@ -131,12 +133,13 @@ TEST(MinidumpFileWriter, OneStream) {
TEST(MinidumpFileWriter, AddUserExtensionStream) {
MinidumpFileWriter minidump_file;
const time_t kTimestamp = 0x155d2fb8;
constexpr time_t kTimestamp = 0x155d2fb8;
minidump_file.SetTimestamp(kTimestamp);
static const uint8_t kStreamData[] = "Hello World!";
const size_t kStreamSize = arraysize(kStreamData);
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
static constexpr uint8_t kStreamData[] = "Hello World!";
constexpr size_t kStreamSize = arraysize(kStreamData);
constexpr MinidumpStreamType kStreamType =
static_cast<MinidumpStreamType>(0x4d);
auto data_source = base::WrapUnique(new test::BufferExtensionStreamDataSource(
kStreamType, kStreamData, kStreamSize));
@ -150,9 +153,10 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) {
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kFileSize = kStreamOffset + kStreamSize;
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
constexpr size_t kFileSize = kStreamOffset + kStreamSize;
ASSERT_EQ(string_file.string().size(), kFileSize);
@ -175,10 +179,11 @@ TEST(MinidumpFileWriter, AddUserExtensionStream) {
TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) {
MinidumpFileWriter minidump_file;
const time_t kTimestamp = 0x155d2fb8;
constexpr time_t kTimestamp = 0x155d2fb8;
minidump_file.SetTimestamp(kTimestamp);
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
constexpr MinidumpStreamType kStreamType =
static_cast<MinidumpStreamType>(0x4d);
auto data_source = base::WrapUnique(
new test::BufferExtensionStreamDataSource(kStreamType, nullptr, 0));
@ -187,9 +192,10 @@ TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) {
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kFileSize = kStreamOffset;
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
constexpr size_t kFileSize = kStreamOffset;
ASSERT_EQ(string_file.string().size(), kFileSize);
@ -206,12 +212,13 @@ TEST(MinidumpFileWriter, AddEmptyUserExtensionStream) {
TEST(MinidumpFileWriter, ThreeStreams) {
MinidumpFileWriter minidump_file;
const time_t kTimestamp = 0x155d2fb8;
constexpr time_t kTimestamp = 0x155d2fb8;
minidump_file.SetTimestamp(kTimestamp);
const size_t kStream0Size = 5;
const MinidumpStreamType kStream0Type = static_cast<MinidumpStreamType>(0x6d);
const uint8_t kStream0Value = 0x5a;
constexpr size_t kStream0Size = 5;
constexpr MinidumpStreamType kStream0Type =
static_cast<MinidumpStreamType>(0x6d);
constexpr uint8_t kStream0Value = 0x5a;
auto stream0 = base::WrapUnique(
new TestStream(kStream0Type, kStream0Size, kStream0Value));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream0)));
@ -219,16 +226,18 @@ TEST(MinidumpFileWriter, ThreeStreams) {
// Make the second streams type be a smaller quantity than the first streams
// to test that the streams show up in the order that they were added, not in
// numeric order.
const size_t kStream1Size = 3;
const MinidumpStreamType kStream1Type = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStream1Value = 0xa5;
constexpr size_t kStream1Size = 3;
constexpr MinidumpStreamType kStream1Type =
static_cast<MinidumpStreamType>(0x4d);
constexpr uint8_t kStream1Value = 0xa5;
auto stream1 = base::WrapUnique(
new TestStream(kStream1Type, kStream1Size, kStream1Value));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream1)));
const size_t kStream2Size = 1;
const MinidumpStreamType kStream2Type = static_cast<MinidumpStreamType>(0x7e);
const uint8_t kStream2Value = 0x36;
constexpr size_t kStream2Size = 1;
constexpr MinidumpStreamType kStream2Type =
static_cast<MinidumpStreamType>(0x7e);
constexpr uint8_t kStream2Value = 0x36;
auto stream2 = base::WrapUnique(
new TestStream(kStream2Type, kStream2Size, kStream2Value));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream2)));
@ -236,14 +245,16 @@ TEST(MinidumpFileWriter, ThreeStreams) {
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStream0Offset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStream0Offset =
kDirectoryOffset + 3 * sizeof(MINIDUMP_DIRECTORY);
const size_t kStream1Padding = 3;
const size_t kStream1Offset = kStream0Offset + kStream0Size + kStream1Padding;
const size_t kStream2Padding = 1;
const size_t kStream2Offset = kStream1Offset + kStream1Size + kStream2Padding;
const size_t kFileSize = kStream2Offset + kStream2Size;
constexpr size_t kStream1Padding = 3;
constexpr size_t kStream1Offset =
kStream0Offset + kStream0Size + kStream1Padding;
constexpr size_t kStream2Padding = 1;
constexpr size_t kStream2Offset =
kStream1Offset + kStream1Size + kStream2Padding;
constexpr size_t kFileSize = kStream2Offset + kStream2Size;
ASSERT_EQ(string_file.string().size(), kFileSize);
@ -270,7 +281,7 @@ TEST(MinidumpFileWriter, ThreeStreams) {
std::string expected_stream0(kStream0Size, kStream0Value);
EXPECT_EQ(memcmp(stream0_data, expected_stream0.c_str(), kStream0Size), 0);
const int kZeroes[16] = {};
static constexpr int kZeroes[16] = {};
ASSERT_GE(sizeof(kZeroes), kStream1Padding);
EXPECT_EQ(memcmp(stream0_data + kStream0Size, kZeroes, kStream1Padding), 0);
@ -295,17 +306,19 @@ TEST(MinidumpFileWriter, ThreeStreams) {
TEST(MinidumpFileWriter, ZeroLengthStream) {
MinidumpFileWriter minidump_file;
const size_t kStreamSize = 0;
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
constexpr size_t kStreamSize = 0;
constexpr MinidumpStreamType kStreamType =
static_cast<MinidumpStreamType>(0x4d);
auto stream = base::WrapUnique(new TestStream(kStreamType, kStreamSize, 0));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream)));
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStreamOffset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kFileSize = kStreamOffset + kStreamSize;
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
constexpr size_t kFileSize = kStreamOffset + kStreamSize;
ASSERT_EQ(string_file.string().size(), kFileSize);
@ -321,8 +334,8 @@ TEST(MinidumpFileWriter, ZeroLengthStream) {
}
TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
const uint32_t kSnapshotTime = 0x4976043c;
const timeval kSnapshotTimeval = { static_cast<time_t>(kSnapshotTime), 0 };
constexpr uint32_t kSnapshotTime = 0x4976043c;
constexpr timeval kSnapshotTimeval = {static_cast<time_t>(kSnapshotTime), 0};
TestProcessSnapshot process_snapshot;
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
@ -333,9 +346,9 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
process_snapshot.SetSystem(std::move(system_snapshot));
auto peb_snapshot = base::WrapUnique(new TestMemorySnapshot());
const uint64_t kPebAddress = 0x07f90000;
constexpr uint64_t kPebAddress = 0x07f90000;
peb_snapshot->SetAddress(kPebAddress);
const size_t kPebSize = 0x280;
constexpr size_t kPebSize = 0x280;
peb_snapshot->SetSize(kPebSize);
peb_snapshot->SetValue('p');
process_snapshot.AddExtraMemory(std::move(peb_snapshot));
@ -383,10 +396,10 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) {
// In a 32-bit environment, this will give a “timestamp out of range” warning,
// but the test should complete without failure.
const uint32_t kSnapshotTime = 0xfd469ab8;
constexpr uint32_t kSnapshotTime = 0xfd469ab8;
MSVC_SUPPRESS_WARNING(4309); // Truncation of constant value.
MSVC_SUPPRESS_WARNING(4838); // Narrowing conversion.
const timeval kSnapshotTimeval = { static_cast<time_t>(kSnapshotTime), 0 };
constexpr timeval kSnapshotTimeval = {static_cast<time_t>(kSnapshotTime), 0};
TestProcessSnapshot process_snapshot;
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
@ -449,8 +462,8 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) {
}
TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) {
const uint32_t kSnapshotTime = 0x15393bd3;
const timeval kSnapshotTimeval = { static_cast<time_t>(kSnapshotTime), 0 };
constexpr uint32_t kSnapshotTime = 0x15393bd3;
constexpr timeval kSnapshotTimeval = {static_cast<time_t>(kSnapshotTime), 0};
TestProcessSnapshot process_snapshot;
process_snapshot.SetSnapshotTime(kSnapshotTimeval);
@ -519,16 +532,17 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_CrashpadInfo) {
TEST(MinidumpFileWriter, SameStreamType) {
MinidumpFileWriter minidump_file;
const size_t kStream0Size = 3;
const MinidumpStreamType kStreamType = static_cast<MinidumpStreamType>(0x4d);
const uint8_t kStream0Value = 0x5a;
constexpr size_t kStream0Size = 3;
constexpr MinidumpStreamType kStreamType =
static_cast<MinidumpStreamType>(0x4d);
constexpr uint8_t kStream0Value = 0x5a;
auto stream0 = base::WrapUnique(
new TestStream(kStreamType, kStream0Size, kStream0Value));
ASSERT_TRUE(minidump_file.AddStream(std::move(stream0)));
// An attempt to add a second stream of the same type should fail.
const size_t kStream1Size = 5;
const uint8_t kStream1Value = 0xa5;
constexpr size_t kStream1Size = 5;
constexpr uint8_t kStream1Value = 0xa5;
auto stream1 = base::WrapUnique(
new TestStream(kStreamType, kStream1Size, kStream1Value));
ASSERT_FALSE(minidump_file.AddStream(std::move(stream1)));
@ -536,9 +550,10 @@ TEST(MinidumpFileWriter, SameStreamType) {
StringFile string_file;
ASSERT_TRUE(minidump_file.WriteEverything(&string_file));
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kStream0Offset = kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kFileSize = kStream0Offset + kStream0Size;
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kStream0Offset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
constexpr size_t kFileSize = kStream0Offset + kStream0Size;
ASSERT_EQ(string_file.string().size(), kFileSize);

View File

@ -34,8 +34,8 @@ namespace {
void GetHandleDataStream(
const std::string& file_contents,
const MINIDUMP_HANDLE_DATA_STREAM** handle_data_stream) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kHandleDataStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kHandleDataStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const MINIDUMP_DIRECTORY* directory;
@ -44,7 +44,7 @@ void GetHandleDataStream(
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
ASSERT_TRUE(directory);
const size_t kDirectoryIndex = 0;
constexpr size_t kDirectoryIndex = 0;
ASSERT_EQ(directory[kDirectoryIndex].StreamType,
kMinidumpStreamTypeHandleData);

View File

@ -33,8 +33,8 @@ namespace {
void GetMemoryInfoListStream(
const std::string& file_contents,
const MINIDUMP_MEMORY_INFO_LIST** memory_info_list) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kMemoryInfoListStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kMemoryInfoListStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const MINIDUMP_DIRECTORY* directory;
@ -43,7 +43,7 @@ void GetMemoryInfoListStream(
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
ASSERT_TRUE(directory);
const size_t kDirectoryIndex = 0;
constexpr size_t kDirectoryIndex = 0;
ASSERT_EQ(directory[kDirectoryIndex].StreamType,
kMinidumpStreamTypeMemoryInfoList);

View File

@ -35,7 +35,7 @@ namespace crashpad {
namespace test {
namespace {
const MinidumpStreamType kBogusStreamType =
constexpr MinidumpStreamType kBogusStreamType =
static_cast<MinidumpStreamType>(1234);
// expected_streams is the expected number of streams in the file. The memory
@ -44,7 +44,7 @@ const MinidumpStreamType kBogusStreamType =
void GetMemoryListStream(const std::string& file_contents,
const MINIDUMP_MEMORY_LIST** memory_list,
const uint32_t expected_streams) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kMemoryListStreamOffset =
kDirectoryOffset + expected_streams * sizeof(MINIDUMP_DIRECTORY);
const size_t kMemoryDescriptorsOffset =
@ -99,9 +99,9 @@ TEST(MinidumpMemoryWriter, OneMemoryRegion) {
MinidumpFileWriter minidump_file_writer;
auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter());
const uint64_t kBaseAddress = 0xfedcba9876543210;
const uint64_t kSize = 0x1000;
const uint8_t kValue = 'm';
constexpr uint64_t kBaseAddress = 0xfedcba9876543210;
constexpr uint64_t kSize = 0x1000;
constexpr uint8_t kValue = 'm';
auto memory_writer = base::WrapUnique(
new TestMinidumpMemoryWriter(kBaseAddress, kSize, kValue));
@ -134,12 +134,12 @@ TEST(MinidumpMemoryWriter, TwoMemoryRegions) {
MinidumpFileWriter minidump_file_writer;
auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter());
const uint64_t kBaseAddress0 = 0xc0ffee;
const uint64_t kSize0 = 0x0100;
const uint8_t kValue0 = '6';
const uint64_t kBaseAddress1 = 0xfac00fac;
const uint64_t kSize1 = 0x0200;
const uint8_t kValue1 = '!';
constexpr uint64_t kBaseAddress0 = 0xc0ffee;
constexpr uint64_t kSize0 = 0x0100;
constexpr uint8_t kValue0 = '6';
constexpr uint64_t kBaseAddress1 = 0xfac00fac;
constexpr uint64_t kSize1 = 0x0200;
constexpr uint8_t kValue1 = '!';
auto memory_writer_0 = base::WrapUnique(
new TestMinidumpMemoryWriter(kBaseAddress0, kSize0, kValue0));
@ -238,9 +238,9 @@ TEST(MinidumpMemoryWriter, ExtraMemory) {
// memory writer a child of the memory list writer.
MinidumpFileWriter minidump_file_writer;
const uint64_t kBaseAddress0 = 0x1000;
const size_t kSize0 = 0x0400;
const uint8_t kValue0 = '1';
constexpr uint64_t kBaseAddress0 = 0x1000;
constexpr size_t kSize0 = 0x0400;
constexpr uint8_t kValue0 = '1';
auto test_memory_stream =
base::WrapUnique(new TestMemoryStream(kBaseAddress0, kSize0, kValue0));
@ -249,9 +249,9 @@ TEST(MinidumpMemoryWriter, ExtraMemory) {
ASSERT_TRUE(minidump_file_writer.AddStream(std::move(test_memory_stream)));
const uint64_t kBaseAddress1 = 0x2000;
const size_t kSize1 = 0x0400;
const uint8_t kValue1 = 'm';
constexpr uint64_t kBaseAddress1 = 0x2000;
constexpr size_t kSize1 = 0x0400;
constexpr uint8_t kValue1 = 'm';
auto memory_writer = base::WrapUnique(
new TestMinidumpMemoryWriter(kBaseAddress1, kSize1, kValue1));

View File

@ -42,7 +42,7 @@ namespace {
uint32_t TimevalToRoundedSeconds(const timeval& tv) {
uint32_t seconds =
InRangeCast<uint32_t>(tv.tv_sec, std::numeric_limits<uint32_t>::max());
const int kMicrosecondsPerSecond = static_cast<int>(1E6);
constexpr int kMicrosecondsPerSecond = static_cast<int>(1E6);
if (tv.tv_usec >= kMicrosecondsPerSecond / 2 &&
seconds != std::numeric_limits<uint32_t>::max()) {
++seconds;
@ -101,25 +101,25 @@ std::string MinidumpMiscInfoDebugBuildString() {
// plus a UTF-16 NUL terminator. Dont let strings get longer than this, or
// they will be truncated and a message will be logged.
#if defined(OS_MACOSX)
const char kOS[] = "mac";
static constexpr char kOS[] = "mac";
#elif defined(OS_ANDROID)
const char kOS[] = "android";
static constexpr char kOS[] = "android";
#elif defined(OS_LINUX)
const char kOS[] = "linux";
static constexpr char kOS[] = "linux";
#elif defined(OS_WIN)
const char kOS[] = "win";
static constexpr char kOS[] = "win";
#else
#error define kOS for this operating system
#endif
#if defined(ARCH_CPU_X86)
const char kCPU[] = "i386";
static constexpr char kCPU[] = "i386";
#elif defined(ARCH_CPU_X86_64)
const char kCPU[] = "amd64";
static constexpr char kCPU[] = "amd64";
#elif defined(ARCH_CPU_ARMEL)
const char kCPU[] = "arm";
static constexpr char kCPU[] = "arm";
#elif defined(ARCH_CPU_ARM64)
const char kCPU[] = "arm64";
static constexpr char kCPU[] = "arm64";
#else
#error define kCPU for this CPU
#endif
@ -163,7 +163,7 @@ void MinidumpMiscInfoWriter::InitializeFromSnapshot(
uint64_t current_hz;
uint64_t max_hz;
system_snapshot->CPUFrequency(&current_hz, &max_hz);
const uint32_t kHzPerMHz = static_cast<const uint32_t>(1E6);
constexpr uint32_t kHzPerMHz = static_cast<const uint32_t>(1E6);
SetProcessorPowerInfo(
InRangeCast<uint32_t>(current_hz / kHzPerMHz,
std::numeric_limits<uint32_t>::max()),

View File

@ -43,11 +43,11 @@ namespace {
template <typename T>
void GetMiscInfoStream(const std::string& file_contents, const T** misc_info) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kMiscInfoStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kMiscInfoStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kMiscInfoStreamSize = sizeof(T);
const size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize;
constexpr size_t kMiscInfoStreamSize = sizeof(T);
constexpr size_t kFileSize = kMiscInfoStreamOffset + kMiscInfoStreamSize;
ASSERT_EQ(file_contents.size(), kFileSize);
@ -211,7 +211,7 @@ TEST(MinidumpMiscInfoWriter, ProcessId) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessId = 12345;
constexpr uint32_t kProcessId = 12345;
misc_info_writer->SetProcessID(kProcessId);
@ -234,9 +234,9 @@ TEST(MinidumpMiscInfoWriter, ProcessTimes) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const time_t kProcessCreateTime = 0x15252f00;
const uint32_t kProcessUserTime = 10;
const uint32_t kProcessKernelTime = 5;
constexpr time_t kProcessCreateTime = 0x15252f00;
constexpr uint32_t kProcessUserTime = 10;
constexpr uint32_t kProcessKernelTime = 5;
misc_info_writer->SetProcessTimes(
kProcessCreateTime, kProcessUserTime, kProcessKernelTime);
@ -262,11 +262,11 @@ TEST(MinidumpMiscInfoWriter, ProcessorPowerInfo) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessorMaxMhz = 2800;
const uint32_t kProcessorCurrentMhz = 2300;
const uint32_t kProcessorMhzLimit = 3300;
const uint32_t kProcessorMaxIdleState = 5;
const uint32_t kProcessorCurrentIdleState = 1;
constexpr uint32_t kProcessorMaxMhz = 2800;
constexpr uint32_t kProcessorCurrentMhz = 2300;
constexpr uint32_t kProcessorMhzLimit = 3300;
constexpr uint32_t kProcessorMaxIdleState = 5;
constexpr uint32_t kProcessorCurrentIdleState = 1;
misc_info_writer->SetProcessorPowerInfo(kProcessorMaxMhz,
kProcessorCurrentMhz,
@ -297,7 +297,7 @@ TEST(MinidumpMiscInfoWriter, ProcessIntegrityLevel) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessIntegrityLevel = 0x2000;
constexpr uint32_t kProcessIntegrityLevel = 0x2000;
misc_info_writer->SetProcessIntegrityLevel(kProcessIntegrityLevel);
@ -320,7 +320,7 @@ TEST(MinidumpMiscInfoWriter, ProcessExecuteFlags) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessExecuteFlags = 0x13579bdf;
constexpr uint32_t kProcessExecuteFlags = 0x13579bdf;
misc_info_writer->SetProcessExecuteFlags(kProcessExecuteFlags);
@ -343,7 +343,7 @@ TEST(MinidumpMiscInfoWriter, ProtectedProcess) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProtectedProcess = 1;
constexpr uint32_t kProtectedProcess = 1;
misc_info_writer->SetProtectedProcess(kProtectedProcess);
@ -366,14 +366,14 @@ TEST(MinidumpMiscInfoWriter, TimeZone) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kTimeZoneId = 2;
const int32_t kBias = 300;
const char kStandardName[] = "EST";
const SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0};
const int32_t kStandardBias = 0;
const char kDaylightName[] = "EDT";
const SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0};
const int32_t kDaylightBias = -60;
constexpr uint32_t kTimeZoneId = 2;
constexpr int32_t kBias = 300;
static constexpr char kStandardName[] = "EST";
constexpr SYSTEMTIME kStandardDate = {0, 11, 1, 0, 2, 0, 0, 0};
constexpr int32_t kStandardBias = 0;
static constexpr char kDaylightName[] = "EDT";
constexpr SYSTEMTIME kDaylightDate = {0, 3, 2, 0, 2, 0, 0, 0};
constexpr int32_t kDaylightBias = -60;
misc_info_writer->SetTimeZone(kTimeZoneId,
kBias,
@ -423,19 +423,19 @@ TEST(MinidumpMiscInfoWriter, TimeZoneStringsOverflow) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kTimeZoneId = 2;
const int32_t kBias = 300;
constexpr uint32_t kTimeZoneId = 2;
constexpr int32_t kBias = 300;
MINIDUMP_MISC_INFO_N tmp;
ALLOW_UNUSED_LOCAL(tmp);
std::string standard_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.StandardName) + 1,
's');
const int32_t kStandardBias = 0;
constexpr int32_t kStandardBias = 0;
std::string daylight_name(ARRAYSIZE_UNSAFE(tmp.TimeZone.DaylightName), 'd');
const int32_t kDaylightBias = -60;
constexpr int32_t kDaylightBias = -60;
// Test using kSystemTimeZero, because not all platforms will be able to
// provide daylight saving time transition times.
const SYSTEMTIME kSystemTimeZero = {};
constexpr SYSTEMTIME kSystemTimeZero = {};
misc_info_writer->SetTimeZone(kTimeZoneId,
kBias,
@ -482,8 +482,8 @@ TEST(MinidumpMiscInfoWriter, BuildStrings) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const char kBuildString[] = "build string";
const char kDebugBuildString[] = "debug build string";
static constexpr char kBuildString[] = "build string";
static constexpr char kDebugBuildString[] = "debug build string";
misc_info_writer->SetBuildString(kBuildString, kDebugBuildString);
@ -551,7 +551,7 @@ TEST(MinidumpMiscInfoWriter, XStateData) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = {
constexpr XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = {
sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO),
1024,
0x000000000000005f,
@ -585,7 +585,7 @@ TEST(MinidumpMiscInfoWriter, ProcessCookie) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessCookie = 0x12345678;
constexpr uint32_t kProcessCookie = 0x12345678;
misc_info_writer->SetProcessCookie(kProcessCookie);
@ -608,27 +608,27 @@ TEST(MinidumpMiscInfoWriter, Everything) {
MinidumpFileWriter minidump_file_writer;
auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
const uint32_t kProcessId = 12345;
const time_t kProcessCreateTime = 0x15252f00;
const uint32_t kProcessUserTime = 10;
const uint32_t kProcessKernelTime = 5;
const uint32_t kProcessorMaxMhz = 2800;
const uint32_t kProcessorCurrentMhz = 2300;
const uint32_t kProcessorMhzLimit = 3300;
const uint32_t kProcessorMaxIdleState = 5;
const uint32_t kProcessorCurrentIdleState = 1;
const uint32_t kProcessIntegrityLevel = 0x2000;
const uint32_t kProcessExecuteFlags = 0x13579bdf;
const uint32_t kProtectedProcess = 1;
const uint32_t kTimeZoneId = 2;
const int32_t kBias = 300;
const char kStandardName[] = "EST";
const int32_t kStandardBias = 0;
const char kDaylightName[] = "EDT";
const int32_t kDaylightBias = -60;
const SYSTEMTIME kSystemTimeZero = {};
const char kBuildString[] = "build string";
const char kDebugBuildString[] = "debug build string";
constexpr uint32_t kProcessId = 12345;
constexpr time_t kProcessCreateTime = 0x15252f00;
constexpr uint32_t kProcessUserTime = 10;
constexpr uint32_t kProcessKernelTime = 5;
constexpr uint32_t kProcessorMaxMhz = 2800;
constexpr uint32_t kProcessorCurrentMhz = 2300;
constexpr uint32_t kProcessorMhzLimit = 3300;
constexpr uint32_t kProcessorMaxIdleState = 5;
constexpr uint32_t kProcessorCurrentIdleState = 1;
constexpr uint32_t kProcessIntegrityLevel = 0x2000;
constexpr uint32_t kProcessExecuteFlags = 0x13579bdf;
constexpr uint32_t kProtectedProcess = 1;
constexpr uint32_t kTimeZoneId = 2;
constexpr int32_t kBias = 300;
static constexpr char kStandardName[] = "EST";
constexpr int32_t kStandardBias = 0;
static constexpr char kDaylightName[] = "EDT";
constexpr int32_t kDaylightBias = -60;
constexpr SYSTEMTIME kSystemTimeZero = {};
static constexpr char kBuildString[] = "build string";
static constexpr char kDebugBuildString[] = "debug build string";
misc_info_writer->SetProcessID(kProcessId);
misc_info_writer->SetProcessTimes(
@ -711,14 +711,15 @@ TEST(MinidumpMiscInfoWriter, Everything) {
TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) {
MINIDUMP_MISC_INFO_4 expect_misc_info = {};
const char kStandardTimeName[] = "EST";
const char kDaylightTimeName[] = "EDT";
const char kOSVersionFull[] =
static constexpr char kStandardTimeName[] = "EST";
static constexpr char kDaylightTimeName[] = "EDT";
static constexpr char kOSVersionFull[] =
"Mac OS X 10.9.5 (13F34); "
"Darwin 13.4.0 Darwin Kernel Version 13.4.0: "
"Sun Aug 17 19:50:11 PDT 2014; "
"root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64";
const char kMachineDescription[] = "MacBookPro11,3 (Mac-2BD1B31983FE1663)";
static constexpr char kMachineDescription[] =
"MacBookPro11,3 (Mac-2BD1B31983FE1663)";
base::string16 standard_time_name_utf16 =
base::UTF8ToUTF16(kStandardTimeName);
base::string16 daylight_time_name_utf16 =
@ -772,7 +773,7 @@ TEST(MinidumpMiscInfoWriter, InitializeFromSnapshot) {
process_snapshot.SetProcessCPUTimes(kUserCPUTime, kSystemCPUTime);
auto system_snapshot = base::WrapUnique(new TestSystemSnapshot());
const uint64_t kHzPerMHz = static_cast<uint64_t>(1E6);
constexpr uint64_t kHzPerMHz = static_cast<uint64_t>(1E6);
system_snapshot->SetCPUFrequency(
expect_misc_info.ProcessorCurrentMhz * kHzPerMHz,
expect_misc_info.ProcessorMaxMhz * kHzPerMHz);

View File

@ -108,10 +108,10 @@ TEST(MinidumpModuleCrashpadInfoWriter, EmptyModule) {
}
TEST(MinidumpModuleCrashpadInfoWriter, FullModule) {
const uint32_t kMinidumpModuleListIndex = 1;
const char kKey[] = "key";
const char kValue[] = "value";
const char kEntry[] = "entry";
constexpr uint32_t kMinidumpModuleListIndex = 1;
static constexpr char kKey[] = "key";
static constexpr char kValue[] = "value";
static constexpr char kEntry[] = "entry";
std::vector<std::string> vector(1, std::string(kEntry));
StringFile string_file;
@ -194,15 +194,15 @@ TEST(MinidumpModuleCrashpadInfoWriter, FullModule) {
}
TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) {
const uint32_t kMinidumpModuleListIndex0 = 0;
const char kKey0[] = "key";
const char kValue0[] = "value";
const uint32_t kMinidumpModuleListIndex1 = 2;
const uint32_t kMinidumpModuleListIndex2 = 5;
const char kKey2A[] = "K";
const char kValue2A[] = "VVV";
const char kKey2B[] = "river";
const char kValue2B[] = "hudson";
constexpr uint32_t kMinidumpModuleListIndex0 = 0;
static constexpr char kKey0[] = "key";
static constexpr char kValue0[] = "value";
constexpr uint32_t kMinidumpModuleListIndex1 = 2;
constexpr uint32_t kMinidumpModuleListIndex2 = 5;
static constexpr char kKey2A[] = "K";
static constexpr char kValue2A[] = "VVV";
static constexpr char kKey2B[] = "river";
static constexpr char kValue2B[] = "hudson";
StringFile string_file;
@ -339,14 +339,14 @@ TEST(MinidumpModuleCrashpadInfoWriter, ThreeModules) {
}
TEST(MinidumpModuleCrashpadInfoWriter, InitializeFromSnapshot) {
const char kKey0A[] = "k";
const char kValue0A[] = "value";
const char kKey0B[] = "hudson";
const char kValue0B[] = "estuary";
const char kKey2[] = "k";
const char kValue2[] = "different_value";
const char kEntry3A[] = "list";
const char kEntry3B[] = "erine";
static constexpr char kKey0A[] = "k";
static constexpr char kValue0A[] = "value";
static constexpr char kKey0B[] = "hudson";
static constexpr char kValue0B[] = "estuary";
static constexpr char kKey2[] = "k";
static constexpr char kValue2[] = "different_value";
static constexpr char kEntry3A[] = "list";
static constexpr char kEntry3B[] = "erine";
std::vector<const ModuleSnapshot*> module_snapshots;

View File

@ -42,10 +42,10 @@ namespace {
void GetModuleListStream(const std::string& file_contents,
const MINIDUMP_MODULE_LIST** module_list) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kModuleListStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kModuleListStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kModulesOffset =
constexpr size_t kModulesOffset =
kModuleListStreamOffset + sizeof(MINIDUMP_MODULE_LIST);
ASSERT_GE(file_contents.size(), kModulesOffset);
@ -271,7 +271,7 @@ TEST(MinidumpModuleWriter, EmptyModule) {
MinidumpFileWriter minidump_file_writer;
auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter());
const char kModuleName[] = "test_executable";
static constexpr char kModuleName[] = "test_executable";
auto module_writer = base::WrapUnique(new MinidumpModuleWriter());
module_writer->SetName(kModuleName);
@ -310,32 +310,32 @@ TEST(MinidumpModuleWriter, OneModule) {
MinidumpFileWriter minidump_file_writer;
auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter());
const char kModuleName[] = "statically_linked";
const uint64_t kModuleBase = 0x10da69000;
const uint32_t kModuleSize = 0x1000;
const uint32_t kChecksum = 0x76543210;
const time_t kTimestamp = 0x386d4380;
const uint32_t kFileVersionMS = 0x00010002;
const uint32_t kFileVersionLS = 0x00030004;
const uint32_t kProductVersionMS = 0x00050006;
const uint32_t kProductVersionLS = 0x00070008;
const uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE |
VS_FF_PATCHED | VS_FF_PRIVATEBUILD |
VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD;
const uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD;
const uint32_t kFileOS = VOS_DOS;
const uint32_t kFileType = VFT_DRV;
const uint32_t kFileSubtype = VFT2_DRV_KEYBOARD;
const char kPDBName[] = "statical.pdb";
const uint8_t kPDBUUIDBytes[16] =
static constexpr char kModuleName[] = "statically_linked";
constexpr uint64_t kModuleBase = 0x10da69000;
constexpr uint32_t kModuleSize = 0x1000;
constexpr uint32_t kChecksum = 0x76543210;
constexpr time_t kTimestamp = 0x386d4380;
constexpr uint32_t kFileVersionMS = 0x00010002;
constexpr uint32_t kFileVersionLS = 0x00030004;
constexpr uint32_t kProductVersionMS = 0x00050006;
constexpr uint32_t kProductVersionLS = 0x00070008;
constexpr uint32_t kFileFlagsMask = VS_FF_DEBUG | VS_FF_PRERELEASE |
VS_FF_PATCHED | VS_FF_PRIVATEBUILD |
VS_FF_INFOINFERRED | VS_FF_SPECIALBUILD;
constexpr uint32_t kFileFlags = VS_FF_PRIVATEBUILD | VS_FF_SPECIALBUILD;
constexpr uint32_t kFileOS = VOS_DOS;
constexpr uint32_t kFileType = VFT_DRV;
constexpr uint32_t kFileSubtype = VFT2_DRV_KEYBOARD;
static constexpr char kPDBName[] = "statical.pdb";
static constexpr uint8_t kPDBUUIDBytes[16] =
{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
0x08, 0x19, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x7f};
UUID pdb_uuid;
pdb_uuid.InitializeFromBytes(kPDBUUIDBytes);
const uint32_t kPDBAge = 1;
const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
const char kDebugName[] = "statical.dbg";
const bool kDebugUTF16 = false;
constexpr uint32_t kPDBAge = 1;
constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
static constexpr char kDebugName[] = "statical.dbg";
constexpr bool kDebugUTF16 = false;
auto module_writer = base::WrapUnique(new MinidumpModuleWriter());
module_writer->SetName(kModuleName);
@ -419,13 +419,13 @@ TEST(MinidumpModuleWriter, OneModule_CodeViewUsesPDB20_MiscUsesUTF16) {
MinidumpFileWriter minidump_file_writer;
auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter());
const char kModuleName[] = "dinosaur";
const char kPDBName[] = "d1n05.pdb";
const time_t kPDBTimestamp = 0x386d4380;
const uint32_t kPDBAge = 1;
const uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
const char kDebugName[] = "d1n05.dbg";
const bool kDebugUTF16 = true;
static constexpr char kModuleName[] = "dinosaur";
static constexpr char kPDBName[] = "d1n05.pdb";
constexpr time_t kPDBTimestamp = 0x386d4380;
constexpr uint32_t kPDBAge = 1;
constexpr uint32_t kDebugType = IMAGE_DEBUG_MISC_EXENAME;
static constexpr char kDebugName[] = "d1n05.dbg";
constexpr bool kDebugUTF16 = true;
auto module_writer = base::WrapUnique(new MinidumpModuleWriter());
module_writer->SetName(kModuleName);
@ -480,27 +480,27 @@ TEST(MinidumpModuleWriter, ThreeModules) {
MinidumpFileWriter minidump_file_writer;
auto module_list_writer = base::WrapUnique(new MinidumpModuleListWriter());
const char kModuleName0[] = "main";
const uint64_t kModuleBase0 = 0x100101000;
const uint32_t kModuleSize0 = 0xf000;
const char kPDBName0[] = "main";
const uint8_t kPDBUUIDBytes0[16] =
static constexpr char kModuleName0[] = "main";
constexpr uint64_t kModuleBase0 = 0x100101000;
constexpr uint32_t kModuleSize0 = 0xf000;
static constexpr char kPDBName0[] = "main";
static constexpr uint8_t kPDBUUIDBytes0[16] =
{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11,
0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
UUID pdb_uuid_0;
pdb_uuid_0.InitializeFromBytes(kPDBUUIDBytes0);
const uint32_t kPDBAge0 = 0;
constexpr uint32_t kPDBAge0 = 0;
const char kModuleName1[] = "ld.so";
const uint64_t kModuleBase1 = 0x200202000;
const uint32_t kModuleSize1 = 0x1e000;
static constexpr char kModuleName1[] = "ld.so";
constexpr uint64_t kModuleBase1 = 0x200202000;
constexpr uint32_t kModuleSize1 = 0x1e000;
const char kModuleName2[] = "libc.so";
const uint64_t kModuleBase2 = 0x300303000;
const uint32_t kModuleSize2 = 0x2d000;
const char kPDBName2[] = "libc.so";
const time_t kPDBTimestamp2 = 0x386d4380;
const uint32_t kPDBAge2 = 2;
static constexpr char kModuleName2[] = "libc.so";
constexpr uint64_t kModuleBase2 = 0x300303000;
constexpr uint32_t kModuleSize2 = 0x2d000;
static constexpr char kPDBName2[] = "libc.so";
constexpr time_t kPDBTimestamp2 = 0x386d4380;
constexpr uint32_t kPDBAge2 = 2;
auto module_writer_0 = base::WrapUnique(new MinidumpModuleWriter());
module_writer_0->SetName(kModuleName0);
@ -668,7 +668,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
expect_modules[0].VersionInfo.dwFileType = VFT_APP;
module_paths[0] = "/usr/bin/true";
module_pdbs[0] = "true";
const uint8_t kUUIDBytes0[16] =
static constexpr uint8_t kUUIDBytes0[16] =
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
uuids[0].InitializeFromBytes(kUUIDBytes0);
@ -684,7 +684,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
expect_modules[1].VersionInfo.dwFileType = VFT_DLL;
module_paths[1] = "/usr/lib/libSystem.B.dylib";
module_pdbs[1] = "libSystem.B.dylib.pdb";
const uint8_t kUUIDBytes1[16] =
static constexpr uint8_t kUUIDBytes1[16] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
uuids[1].InitializeFromBytes(kUUIDBytes1);
@ -700,7 +700,7 @@ TEST(MinidumpModuleWriter, InitializeFromSnapshot) {
expect_modules[2].VersionInfo.dwFileType = VFT_UNKNOWN;
module_paths[2] = "/usr/lib/dyld";
module_pdbs[2] = "/usr/lib/dyld.pdb";
const uint8_t kUUIDBytes2[16] =
static constexpr uint8_t kUUIDBytes2[16] =
{0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0};
uuids[2].InitializeFromBytes(kUUIDBytes2);

View File

@ -57,7 +57,7 @@ TEST(MinidumpRVAListWriter, Empty) {
TEST(MinidumpRVAListWriter, OneChild) {
TestMinidumpRVAListWriter list_writer;
const uint32_t kValue = 0;
constexpr uint32_t kValue = 0;
list_writer.AddChild(kValue);
StringFile string_file;
@ -76,7 +76,7 @@ TEST(MinidumpRVAListWriter, OneChild) {
TEST(MinidumpRVAListWriter, ThreeChildren) {
TestMinidumpRVAListWriter list_writer;
const uint32_t kValues[] = { 0x80000000, 0x55555555, 0x66006600 };
static constexpr uint32_t kValues[] = {0x80000000, 0x55555555, 0x66006600};
list_writer.AddChild(kValues[0]);
list_writer.AddChild(kValues[1]);

View File

@ -49,7 +49,7 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
base::string16());
}
const struct {
static constexpr struct {
size_t input_length;
const char* input_string;
size_t output_length;
@ -106,7 +106,7 @@ TEST(MinidumpStringWriter, MinidumpUTF16StringWriter) {
TEST(MinidumpStringWriter, ConvertInvalidUTF8ToUTF16) {
StringFile string_file;
const char* kTestData[] = {
static constexpr const char* kTestData[] = {
"\200", // continuation byte
"\300", // start byte followed by EOF
"\310\177", // start byte without continuation
@ -160,7 +160,7 @@ TEST(MinidumpStringWriter, MinidumpUTF8StringWriter) {
std::string());
}
const struct {
static constexpr struct {
size_t length;
const char* string;
} kTestData[] = {

View File

@ -46,10 +46,10 @@ void GetSystemInfoStream(const std::string& file_contents,
const size_t kCSDVersionBytesWithNUL =
kCSDVersionBytes + sizeof(tmp.Buffer[0]);
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kSystemInfoStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kSystemInfoStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kCSDVersionOffset =
constexpr size_t kCSDVersionOffset =
kSystemInfoStreamOffset + sizeof(MINIDUMP_SYSTEM_INFO);
const size_t kFileSize =
kCSDVersionOffset + sizeof(MINIDUMP_STRING) + kCSDVersionBytesWithNUL;
@ -120,21 +120,22 @@ TEST(MinidumpSystemInfoWriter, X86_Win) {
MinidumpFileWriter minidump_file_writer;
auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter());
const MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureX86;
const uint16_t kCPULevel = 0x0010;
const uint16_t kCPURevision = 0x0602;
const uint8_t kCPUCount = 1;
const MinidumpOS kOS = kMinidumpOSWin32NT;
const MinidumpOSType kOSType = kMinidumpOSTypeWorkstation;
const uint32_t kOSVersionMajor = 6;
const uint32_t kOSVersionMinor = 1;
const uint32_t kOSVersionBuild = 7601;
const char kCSDVersion[] = "Service Pack 1";
const uint16_t kSuiteMask = VER_SUITE_SINGLEUSERTS;
const char kCPUVendor[] = "AuthenticAMD";
const uint32_t kCPUVersion = 0x00100f62;
const uint32_t kCPUFeatures = 0x078bfbff;
const uint32_t kAMDFeatures = 0xefd3fbff;
constexpr MinidumpCPUArchitecture kCPUArchitecture =
kMinidumpCPUArchitectureX86;
constexpr uint16_t kCPULevel = 0x0010;
constexpr uint16_t kCPURevision = 0x0602;
constexpr uint8_t kCPUCount = 1;
constexpr MinidumpOS kOS = kMinidumpOSWin32NT;
constexpr MinidumpOSType kOSType = kMinidumpOSTypeWorkstation;
constexpr uint32_t kOSVersionMajor = 6;
constexpr uint32_t kOSVersionMinor = 1;
constexpr uint32_t kOSVersionBuild = 7601;
static constexpr char kCSDVersion[] = "Service Pack 1";
constexpr uint16_t kSuiteMask = VER_SUITE_SINGLEUSERTS;
static constexpr char kCPUVendor[] = "AuthenticAMD";
constexpr uint32_t kCPUVersion = 0x00100f62;
constexpr uint32_t kCPUFeatures = 0x078bfbff;
constexpr uint32_t kAMDFeatures = 0xefd3fbff;
uint32_t cpu_vendor_registers[3];
ASSERT_EQ(strlen(kCPUVendor), sizeof(cpu_vendor_registers));
@ -190,18 +191,18 @@ TEST(MinidumpSystemInfoWriter, AMD64_Mac) {
MinidumpFileWriter minidump_file_writer;
auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter());
const MinidumpCPUArchitecture kCPUArchitecture =
constexpr MinidumpCPUArchitecture kCPUArchitecture =
kMinidumpCPUArchitectureAMD64;
const uint16_t kCPULevel = 0x0006;
const uint16_t kCPURevision = 0x3a09;
const uint8_t kCPUCount = 8;
const MinidumpOS kOS = kMinidumpOSMacOSX;
const MinidumpOSType kOSType = kMinidumpOSTypeWorkstation;
const uint32_t kOSVersionMajor = 10;
const uint32_t kOSVersionMinor = 9;
const uint32_t kOSVersionBuild = 4;
const char kCSDVersion[] = "13E28";
const uint64_t kCPUFeatures[2] = {0x10427f4c, 0x00000000};
constexpr uint16_t kCPULevel = 0x0006;
constexpr uint16_t kCPURevision = 0x3a09;
constexpr uint8_t kCPUCount = 8;
constexpr MinidumpOS kOS = kMinidumpOSMacOSX;
constexpr MinidumpOSType kOSType = kMinidumpOSTypeWorkstation;
constexpr uint32_t kOSVersionMajor = 10;
constexpr uint32_t kOSVersionMinor = 9;
constexpr uint32_t kOSVersionBuild = 4;
static constexpr char kCSDVersion[] = "13E28";
static constexpr uint64_t kCPUFeatures[2] = {0x10427f4c, 0x00000000};
system_info_writer->SetCPUArchitecture(kCPUArchitecture);
system_info_writer->SetCPULevelAndRevision(kCPULevel, kCPURevision);
@ -247,8 +248,9 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) {
MinidumpFileWriter minidump_file_writer;
auto system_info_writer = base::WrapUnique(new MinidumpSystemInfoWriter());
const MinidumpCPUArchitecture kCPUArchitecture = kMinidumpCPUArchitectureX86;
const uint32_t kCPUVendor[] = {'uneG', 'Ieni', 'letn'};
constexpr MinidumpCPUArchitecture kCPUArchitecture =
kMinidumpCPUArchitectureX86;
static constexpr uint32_t kCPUVendor[] = {'uneG', 'Ieni', 'letn'};
system_info_writer->SetCPUArchitecture(kCPUArchitecture);
system_info_writer->SetCPUX86Vendor(
@ -277,9 +279,9 @@ TEST(MinidumpSystemInfoWriter, X86_CPUVendorFromRegisters) {
TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) {
MINIDUMP_SYSTEM_INFO expect_system_info = {};
const uint16_t kCPUFamily = 6;
const uint8_t kCPUModel = 70;
const uint8_t kCPUStepping = 1;
constexpr uint16_t kCPUFamily = 6;
constexpr uint8_t kCPUModel = 70;
constexpr uint8_t kCPUStepping = 1;
const uint8_t kCPUBasicFamily =
static_cast<uint8_t>(std::min(kCPUFamily, static_cast<uint16_t>(15)));
@ -291,12 +293,12 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) {
EXPECT_LE(kCPUStepping, 15);
EXPECT_TRUE(kCPUBasicFamily == 6 || kCPUBasicFamily == 15 || kCPUModel <= 15);
const uint8_t kCPUBasicModel = kCPUModel & 0xf;
const uint8_t kCPUExtendedModel = kCPUModel >> 4;
constexpr uint8_t kCPUBasicModel = kCPUModel & 0xf;
constexpr uint8_t kCPUExtendedModel = kCPUModel >> 4;
const uint32_t kCPUSignature =
(kCPUExtendedFamily << 20) | (kCPUExtendedModel << 16) |
(kCPUBasicFamily << 8) | (kCPUBasicModel << 4) | kCPUStepping;
const uint64_t kCPUX86Features = 0x7ffafbffbfebfbff;
constexpr uint64_t kCPUX86Features = 0x7ffafbffbfebfbff;
expect_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureX86;
expect_system_info.ProcessorLevel = kCPUFamily;
expect_system_info.ProcessorRevision = (kCPUModel << 8) | kCPUStepping;
@ -313,8 +315,8 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) {
expect_system_info.Cpu.X86CpuInfo.VersionInformation = kCPUSignature;
expect_system_info.Cpu.X86CpuInfo.FeatureInformation =
kCPUX86Features & 0xffffffff;
const char kCPUVendor[] = "GenuineIntel";
const char kOSVersionBuild[] = "13F34";
static constexpr char kCPUVendor[] = "GenuineIntel";
static constexpr char kOSVersionBuild[] = "13F34";
TestSystemSnapshot system_snapshot;
system_snapshot.SetCPUArchitecture(kCPUArchitectureX86);
@ -379,9 +381,9 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_X86) {
TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) {
MINIDUMP_SYSTEM_INFO expect_system_info = {};
const uint8_t kCPUFamily = 6;
const uint8_t kCPUModel = 70;
const uint8_t kCPUStepping = 1;
constexpr uint8_t kCPUFamily = 6;
constexpr uint8_t kCPUModel = 70;
constexpr uint8_t kCPUStepping = 1;
expect_system_info.ProcessorArchitecture = kMinidumpCPUArchitectureAMD64;
expect_system_info.ProcessorLevel = kCPUFamily;
expect_system_info.ProcessorRevision = (kCPUModel << 8) | kCPUStepping;
@ -408,7 +410,7 @@ TEST(MinidumpSystemInfoWriter, InitializeFromSnapshot_AMD64) {
(1 << PF_RDRAND_INSTRUCTION_AVAILABLE) |
(UINT64_C(1) << PF_RDTSCP_INSTRUCTION_AVAILABLE);
expect_system_info.Cpu.OtherCpuInfo.ProcessorFeatures[1] = 0;
const char kOSVersionBuild[] = "13F34";
static constexpr char kOSVersionBuild[] = "13F34";
TestSystemSnapshot system_snapshot;
system_snapshot.SetCPUArchitecture(kCPUArchitectureX86_64);

View File

@ -46,7 +46,7 @@ namespace {
void GetThreadListStream(const std::string& file_contents,
const MINIDUMP_THREAD_LIST** thread_list,
const MINIDUMP_MEMORY_LIST** memory_list) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const uint32_t kExpectedStreams = memory_list ? 2 : 1;
const size_t kThreadListStreamOffset =
kDirectoryOffset + kExpectedStreams * sizeof(MINIDUMP_DIRECTORY);
@ -142,12 +142,12 @@ TEST(MinidumpThreadWriter, OneThread_x86_NoStack) {
MinidumpFileWriter minidump_file_writer;
auto thread_list_writer = base::WrapUnique(new MinidumpThreadListWriter());
const uint32_t kThreadID = 0x11111111;
const uint32_t kSuspendCount = 1;
const uint32_t kPriorityClass = 0x20;
const uint32_t kPriority = 10;
const uint64_t kTEB = 0x55555555;
const uint32_t kSeed = 123;
constexpr uint32_t kThreadID = 0x11111111;
constexpr uint32_t kSuspendCount = 1;
constexpr uint32_t kPriorityClass = 0x20;
constexpr uint32_t kPriority = 10;
constexpr uint64_t kTEB = 0x55555555;
constexpr uint32_t kSeed = 123;
auto thread_writer = base::WrapUnique(new MinidumpThreadWriter());
thread_writer->SetThreadID(kThreadID);
@ -201,15 +201,15 @@ TEST(MinidumpThreadWriter, OneThread_AMD64_Stack) {
MinidumpFileWriter minidump_file_writer;
auto thread_list_writer = base::WrapUnique(new MinidumpThreadListWriter());
const uint32_t kThreadID = 0x22222222;
const uint32_t kSuspendCount = 2;
const uint32_t kPriorityClass = 0x30;
const uint32_t kPriority = 20;
const uint64_t kTEB = 0x5555555555555555;
const uint64_t kMemoryBase = 0x765432100000;
const size_t kMemorySize = 32;
const uint8_t kMemoryValue = 99;
const uint32_t kSeed = 456;
constexpr uint32_t kThreadID = 0x22222222;
constexpr uint32_t kSuspendCount = 2;
constexpr uint32_t kPriorityClass = 0x30;
constexpr uint32_t kPriority = 20;
constexpr uint64_t kTEB = 0x5555555555555555;
constexpr uint64_t kMemoryBase = 0x765432100000;
constexpr size_t kMemorySize = 32;
constexpr uint8_t kMemoryValue = 99;
constexpr uint32_t kSeed = 456;
auto thread_writer = base::WrapUnique(new MinidumpThreadWriter());
thread_writer->SetThreadID(kThreadID);
@ -282,15 +282,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
auto memory_list_writer = base::WrapUnique(new MinidumpMemoryListWriter());
thread_list_writer->SetMemoryListWriter(memory_list_writer.get());
const uint32_t kThreadID0 = 1111111;
const uint32_t kSuspendCount0 = 111111;
const uint32_t kPriorityClass0 = 11111;
const uint32_t kPriority0 = 1111;
const uint64_t kTEB0 = 111;
const uint64_t kMemoryBase0 = 0x1110;
const size_t kMemorySize0 = 16;
const uint8_t kMemoryValue0 = 11;
const uint32_t kSeed0 = 1;
constexpr uint32_t kThreadID0 = 1111111;
constexpr uint32_t kSuspendCount0 = 111111;
constexpr uint32_t kPriorityClass0 = 11111;
constexpr uint32_t kPriority0 = 1111;
constexpr uint64_t kTEB0 = 111;
constexpr uint64_t kMemoryBase0 = 0x1110;
constexpr size_t kMemorySize0 = 16;
constexpr uint8_t kMemoryValue0 = 11;
constexpr uint32_t kSeed0 = 1;
auto thread_writer_0 = base::WrapUnique(new MinidumpThreadWriter());
thread_writer_0->SetThreadID(kThreadID0);
@ -309,15 +309,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
thread_list_writer->AddThread(std::move(thread_writer_0));
const uint32_t kThreadID1 = 2222222;
const uint32_t kSuspendCount1 = 222222;
const uint32_t kPriorityClass1 = 22222;
const uint32_t kPriority1 = 2222;
const uint64_t kTEB1 = 222;
const uint64_t kMemoryBase1 = 0x2220;
const size_t kMemorySize1 = 32;
const uint8_t kMemoryValue1 = 22;
const uint32_t kSeed1 = 2;
constexpr uint32_t kThreadID1 = 2222222;
constexpr uint32_t kSuspendCount1 = 222222;
constexpr uint32_t kPriorityClass1 = 22222;
constexpr uint32_t kPriority1 = 2222;
constexpr uint64_t kTEB1 = 222;
constexpr uint64_t kMemoryBase1 = 0x2220;
constexpr size_t kMemorySize1 = 32;
constexpr uint8_t kMemoryValue1 = 22;
constexpr uint32_t kSeed1 = 2;
auto thread_writer_1 = base::WrapUnique(new MinidumpThreadWriter());
thread_writer_1->SetThreadID(kThreadID1);
@ -336,15 +336,15 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
thread_list_writer->AddThread(std::move(thread_writer_1));
const uint32_t kThreadID2 = 3333333;
const uint32_t kSuspendCount2 = 333333;
const uint32_t kPriorityClass2 = 33333;
const uint32_t kPriority2 = 3333;
const uint64_t kTEB2 = 333;
const uint64_t kMemoryBase2 = 0x3330;
const size_t kMemorySize2 = 48;
const uint8_t kMemoryValue2 = 33;
const uint32_t kSeed2 = 3;
constexpr uint32_t kThreadID2 = 3333333;
constexpr uint32_t kSuspendCount2 = 333333;
constexpr uint32_t kPriorityClass2 = 33333;
constexpr uint32_t kPriority2 = 3333;
constexpr uint64_t kTEB2 = 333;
constexpr uint64_t kMemoryBase2 = 0x3330;
constexpr size_t kMemorySize2 = 48;
constexpr uint8_t kMemoryValue2 = 33;
constexpr uint32_t kSeed2 = 3;
auto thread_writer_2 = base::WrapUnique(new MinidumpThreadWriter());
thread_writer_2->SetThreadID(kThreadID2);
@ -533,7 +533,7 @@ void RunInitializeFromSnapshotTest(bool thread_id_collision) {
uint32_t context_seeds[arraysize(expect_threads)] = {};
MINIDUMP_MEMORY_DESCRIPTOR tebs[arraysize(expect_threads)] = {};
const size_t kTebSize = 1024;
constexpr size_t kTebSize = 1024;
expect_threads[0].ThreadId = 1;
expect_threads[0].SuspendCount = 2;

View File

@ -46,10 +46,10 @@ void ExpectUnloadedModule(const MINIDUMP_UNLOADED_MODULE* expected,
void GetUnloadedModuleListStream(
const std::string& file_contents,
const MINIDUMP_UNLOADED_MODULE_LIST** unloaded_module_list) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kUnloadedModuleListStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kUnloadedModuleListStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const size_t kUnloadedModulesOffset =
constexpr size_t kUnloadedModulesOffset =
kUnloadedModuleListStreamOffset + sizeof(MINIDUMP_UNLOADED_MODULE_LIST);
ASSERT_GE(file_contents.size(), kUnloadedModulesOffset);
@ -74,7 +74,7 @@ TEST(MinidumpUnloadedModuleWriter, EmptyModule) {
auto unloaded_module_list_writer =
base::WrapUnique(new MinidumpUnloadedModuleListWriter());
const char kModuleName[] = "test_dll";
static constexpr char kModuleName[] = "test_dll";
auto unloaded_module_writer =
base::WrapUnique(new MinidumpUnloadedModuleWriter());
@ -113,11 +113,11 @@ TEST(MinidumpUnloadedModuleWriter, OneModule) {
auto unloaded_module_list_writer =
base::WrapUnique(new MinidumpUnloadedModuleListWriter());
const char kModuleName[] = "statically_linked";
const uint64_t kModuleBase = 0x10da69000;
const uint32_t kModuleSize = 0x1000;
const uint32_t kChecksum = 0x76543210;
const time_t kTimestamp = 0x386d4380;
static constexpr char kModuleName[] = "statically_linked";
constexpr uint64_t kModuleBase = 0x10da69000;
constexpr uint32_t kModuleSize = 0x1000;
constexpr uint32_t kChecksum = 0x76543210;
constexpr time_t kTimestamp = 0x386d4380;
auto unloaded_module_writer =
base::WrapUnique(new MinidumpUnloadedModuleWriter());

View File

@ -35,8 +35,8 @@ void GetUserStream(const std::string& file_contents,
MINIDUMP_LOCATION_DESCRIPTOR* user_stream_location,
uint32_t stream_type,
size_t stream_size) {
const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
const size_t kUserStreamOffset =
constexpr size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
constexpr size_t kUserStreamOffset =
kDirectoryOffset + sizeof(MINIDUMP_DIRECTORY);
const MINIDUMP_DIRECTORY* directory;
@ -45,7 +45,7 @@ void GetUserStream(const std::string& file_contents,
ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, 1, 0));
ASSERT_TRUE(directory);
const size_t kDirectoryIndex = 0;
constexpr size_t kDirectoryIndex = 0;
ASSERT_EQ(directory[kDirectoryIndex].StreamType, stream_type);
EXPECT_EQ(directory[kDirectoryIndex].Location.Rva, kUserStreamOffset);
@ -100,7 +100,7 @@ TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) {
TestMemorySnapshot* test_data = new TestMemorySnapshot();
test_data->SetAddress(97865);
const size_t kStreamSize = 128;
constexpr size_t kStreamSize = 128;
test_data->SetSize(kStreamSize);
test_data->SetValue('c');
auto stream =
@ -125,7 +125,7 @@ TEST(MinidumpUserStreamWriter, InitializeFromSnapshotOneStream) {
TEST(MinidumpUserStreamWriter, InitializeFromBufferOneStream) {
MinidumpFileWriter minidump_file_writer;
const size_t kStreamSize = 128;
constexpr size_t kStreamSize = 128;
std::vector<uint8_t> data(kStreamSize, 'c');
auto data_source = base::WrapUnique(new test::BufferExtensionStreamDataSource(
kTestStreamId, &data[0], data.size()));

View File

@ -16,15 +16,13 @@
#include <stdint.h>
#include <limits>
#include "base/logging.h"
#include "util/file/file_writer.h"
#include "util/numeric/safe_assignment.h"
namespace {
const size_t kMaximumAlignment = 16;
constexpr size_t kMaximumAlignment = 16;
} // namespace
@ -82,9 +80,6 @@ void MinidumpWritable::RegisterLocationDescriptor(
registered_location_descriptors_.push_back(location_descriptor);
}
const size_t MinidumpWritable::kInvalidSize =
std::numeric_limits<size_t>::max();
MinidumpWritable::MinidumpWritable()
: registered_rvas_(),
registered_location_descriptors_(),
@ -248,7 +243,7 @@ bool MinidumpWritable::WritePaddingAndObject(FileWriterInterface* file_writer) {
// The number of elements in kZeroes must be at least one less than the
// maximum Alignment() ever encountered.
const uint8_t kZeroes[kMaximumAlignment - 1] = {};
static constexpr uint8_t kZeroes[kMaximumAlignment - 1] = {};
DCHECK_LE(leading_pad_bytes_, arraysize(kZeroes));
if (leading_pad_bytes_) {

View File

@ -19,6 +19,7 @@
#include <dbghelp.h>
#include <sys/types.h>
#include <limits>
#include <vector>
#include "base/macros.h"
@ -134,7 +135,7 @@ class MinidumpWritable {
//! \brief A size value used to signal failure by methods that return
//! `size_t`.
static const size_t kInvalidSize;
static constexpr size_t kInvalidSize = std::numeric_limits<size_t>::max();
MinidumpWritable();

View File

@ -37,7 +37,7 @@ void ExpectMinidumpMemoryDescriptor(
EXPECT_EQ(observed->StartOfMemoryRange, expected->StartOfMemoryRange);
EXPECT_EQ(observed->Memory.DataSize, expected->Memory.DataSize);
if (expected->Memory.Rva != 0) {
const uint32_t kMemoryAlignment = 16;
constexpr uint32_t kMemoryAlignment = 16;
EXPECT_EQ(observed->Memory.Rva,
(expected->Memory.Rva + kMemoryAlignment - 1) &
~(kMemoryAlignment - 1));

View File

@ -28,7 +28,7 @@ namespace {
void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate,
uint64_t address) {
const uint64_t non_address_offset = 0x10000;
constexpr uint64_t non_address_offset = 0x10000;
if (address < non_address_offset)
return;
@ -38,9 +38,9 @@ void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate,
if (address > max_address - non_address_offset)
return;
const uint64_t kRegisterByteOffset = 128;
constexpr uint64_t kRegisterByteOffset = 128;
const uint64_t target = address - kRegisterByteOffset;
const uint64_t size = 512;
constexpr uint64_t size = 512;
static_assert(kRegisterByteOffset <= size / 2,
"negative offset too large");
auto ranges =

View File

@ -0,0 +1,108 @@
// Copyright 2017 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 "snapshot/linux/cpu_context_linux.h"
#include <stddef.h>
#include <string.h>
#include "base/logging.h"
namespace crashpad {
namespace internal {
#if defined(ARCH_CPU_X86_FAMILY)
void InitializeCPUContextX86(const ThreadContext::t32_t& thread_context,
const FloatContext::f32_t& float_context,
CPUContextX86* context) {
context->eax = thread_context.eax;
context->ebx = thread_context.ebx;
context->ecx = thread_context.ecx;
context->edx = thread_context.edx;
context->edi = thread_context.edi;
context->esi = thread_context.esi;
context->ebp = thread_context.ebp;
context->esp = thread_context.esp;
context->eip = thread_context.eip;
context->eflags = thread_context.eflags;
context->cs = thread_context.xcs;
context->ds = thread_context.xds;
context->es = thread_context.xes;
context->fs = thread_context.xfs;
context->gs = thread_context.xgs;
context->ss = thread_context.xss;
static_assert(sizeof(context->fxsave) == sizeof(float_context.fxsave),
"fxsave size mismatch");
memcpy(&context->fxsave, &float_context.fxsave, sizeof(context->fxsave));
// TODO(jperaza): debug registers
context->dr0 = 0;
context->dr1 = 0;
context->dr2 = 0;
context->dr3 = 0;
context->dr4 = 0;
context->dr5 = 0;
context->dr6 = 0;
context->dr7 = 0;
}
void InitializeCPUContextX86_64(const ThreadContext::t64_t& thread_context,
const FloatContext::f64_t& float_context,
CPUContextX86_64* context) {
context->rax = thread_context.rax;
context->rbx = thread_context.rbx;
context->rcx = thread_context.rcx;
context->rdx = thread_context.rdx;
context->rdi = thread_context.rdi;
context->rsi = thread_context.rsi;
context->rbp = thread_context.rbp;
context->rsp = thread_context.rsp;
context->r8 = thread_context.r8;
context->r9 = thread_context.r9;
context->r10 = thread_context.r10;
context->r11 = thread_context.r11;
context->r12 = thread_context.r12;
context->r13 = thread_context.r13;
context->r14 = thread_context.r14;
context->r15 = thread_context.r15;
context->rip = thread_context.rip;
context->rflags = thread_context.eflags;
context->cs = thread_context.cs;
context->fs = thread_context.fs;
context->gs = thread_context.gs;
static_assert(sizeof(context->fxsave) == sizeof(float_context.fxsave),
"fxsave size mismatch");
memcpy(&context->fxsave, &float_context.fxsave, sizeof(context->fxsave));
// TODO(jperaza): debug registers.
context->dr0 = 0;
context->dr1 = 0;
context->dr2 = 0;
context->dr3 = 0;
context->dr4 = 0;
context->dr5 = 0;
context->dr6 = 0;
context->dr7 = 0;
}
#else
#error Port.
#endif // ARCH_CPU_X86_FAMILY || DOXYGEN
} // namespace internal
} // namespace crashpad

View File

@ -0,0 +1,53 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_
#define CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_
#include "build/build_config.h"
#include "snapshot/cpu_context.h"
#include "util/linux/thread_info.h"
namespace crashpad {
namespace internal {
#if defined(ARCH_CPU_X86_FAMILY) || DOXYGEN
//! \brief Initializes a CPUContextX86 structure from native context structures
//! on Linux.
//!
//! \param[in] thread_context The native thread context.
//! \param[in] float_context The native float context.
//! \param[out] context The CPUContextX86 structure to initialize.
void InitializeCPUContextX86(const ThreadContext::t32_t& thread_context,
const FloatContext::f32_t& float_context,
CPUContextX86* context);
//! \brief Initializes a CPUContextX86_64 structure from native context
//! structures on Linux.
//!
//! \param[in] thread_context The native thread context.
//! \param[in] float_context The native float context.
//! \param[out] context The CPUContextX86_64 structure to initialize.
void InitializeCPUContextX86_64(const ThreadContext::t64_t& thread_context,
const FloatContext::f64_t& float_context,
CPUContextX86_64* context);
#else
#error Port. // TODO(jperaza): ARM
#endif // ARCH_CPU_X86_FAMILY || DOXYGEN
} // namespace internal
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_SNAPSHOT_CPU_CONTEXT_LINUX_H_

View File

@ -0,0 +1,143 @@
// Copyright 2017 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 "snapshot/linux/debug_rendezvous.h"
#include <stdint.h>
#include <set>
#include "base/logging.h"
namespace crashpad {
namespace {
struct Traits32 {
using Integer = int32_t;
using Address = uint32_t;
};
struct Traits64 {
using Integer = int64_t;
using Address = uint64_t;
};
template <typename Traits>
struct DebugRendezvousSpecific {
typename Traits::Integer r_version;
typename Traits::Address r_map;
typename Traits::Address r_brk;
typename Traits::Integer r_state;
typename Traits::Address r_ldbase;
};
template <typename Traits>
struct LinkEntrySpecific {
typename Traits::Address l_addr;
typename Traits::Address l_name;
typename Traits::Address l_ld;
typename Traits::Address l_next;
typename Traits::Address l_prev;
};
template <typename Traits>
bool ReadLinkEntry(const ProcessMemoryRange& memory,
LinuxVMAddress* address,
DebugRendezvous::LinkEntry* entry_out) {
LinkEntrySpecific<Traits> entry;
if (!memory.Read(*address, sizeof(entry), &entry)) {
return false;
}
std::string name;
if (!memory.ReadCStringSizeLimited(entry.l_name, 4096, &name)) {
return false;
}
entry_out->load_bias = entry.l_addr;
entry_out->dynamic_array = entry.l_ld;
entry_out->name.swap(name);
*address = entry.l_next;
return true;
}
} // namespace
DebugRendezvous::LinkEntry::LinkEntry()
: name(), load_bias(0), dynamic_array(0) {}
DebugRendezvous::DebugRendezvous()
: modules_(), executable_(), initialized_() {}
DebugRendezvous::~DebugRendezvous() {}
bool DebugRendezvous::Initialize(const ProcessMemoryRange& memory,
LinuxVMAddress address) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
if (!(memory.Is64Bit() ? InitializeSpecific<Traits64>(memory, address)
: InitializeSpecific<Traits32>(memory, address))) {
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
const DebugRendezvous::LinkEntry* DebugRendezvous::Executable() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &executable_;
}
const std::vector<DebugRendezvous::LinkEntry>& DebugRendezvous::Modules()
const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return modules_;
}
template <typename Traits>
bool DebugRendezvous::InitializeSpecific(const ProcessMemoryRange& memory,
LinuxVMAddress address) {
DebugRendezvousSpecific<Traits> debug;
if (!memory.Read(address, sizeof(debug), &debug)) {
return false;
}
if (debug.r_version != 1) {
LOG(ERROR) << "unexpected version " << debug.r_version;
return false;
}
LinuxVMAddress link_entry_address = debug.r_map;
if (!ReadLinkEntry<Traits>(memory, &link_entry_address, &executable_)) {
return false;
}
std::set<LinuxVMAddress> visited;
while (link_entry_address) {
if (!visited.insert(link_entry_address).second) {
LOG(ERROR) << "cycle at address 0x" << std::hex << link_entry_address;
return false;
}
LinkEntry entry;
if (!ReadLinkEntry<Traits>(memory, &link_entry_address, &entry)) {
return false;
}
modules_.push_back(entry);
}
return true;
}
} // namespace crashpad

View File

@ -0,0 +1,88 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_
#define CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_
#include <string>
#include <vector>
#include "base/macros.h"
#include "util/linux/address_types.h"
#include "util/linux/process_memory_range.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
//! \brief Reads an `r_debug` struct defined in `<link.h>` via
//! ProcessMemoryRange.
class DebugRendezvous {
public:
//! \brief An entry in the dynamic linker's list of loaded objects.
//!
//! All of these values should be checked before use. Whether and how they are
//! populated may vary by dynamic linker.
struct LinkEntry {
LinkEntry();
//! \brief A filename identifying the object.
std::string name;
//! \brief The difference between the preferred load address in the ELF file
//! and the actual loaded address in memory.
LinuxVMOffset load_bias;
//! \brief The address of the dynamic array for this object.
LinuxVMAddress dynamic_array;
};
DebugRendezvous();
~DebugRendezvous();
//! \brief Initializes this object by reading an `r_debug` struct from a
//! target process.
//!
//! This method must be called successfully prior to calling any other method
//! in this class.
//!
//! \param[in] memory A memory reader for the remote process.
//! \param[in] address The address of an `r_debug` struct in the remote
//! process.
//! \return `true` on success. `false` on failure with a message logged.
bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address);
//! \brief Returns the LinkEntry for the main executable.
const LinkEntry* Executable() const;
//! \brief Returns a vector of modules found in the link map.
//!
//! This list excludes the entry for the executable and may include entries
//! for the VDSO and loader.
const std::vector<LinkEntry>& Modules() const;
private:
template <typename Traits>
bool InitializeSpecific(const ProcessMemoryRange& memory,
LinuxVMAddress address);
std::vector<LinkEntry> modules_;
LinkEntry executable_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(DebugRendezvous);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_DEBUG_RENDEZVOUS_H_

View File

@ -0,0 +1,220 @@
// Copyright 2017 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 "snapshot/linux/debug_rendezvous.h"
#include <linux/auxvec.h>
#include <unistd.h>
#include <limits>
#include "base/format_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "snapshot/linux/elf_image_reader.h"
#include "test/multiprocess.h"
#include "util/linux/address_types.h"
#include "util/linux/auxiliary_vector.h"
#include "util/linux/memory_map.h"
#include "util/linux/process_memory.h"
#include "util/linux/process_memory_range.h"
#if defined(OS_ANDROID)
#include <sys/system_properties.h>
#endif
namespace crashpad {
namespace test {
namespace {
#if defined(OS_ANDROID)
int AndroidRuntimeAPI() {
char api_string[PROP_VALUE_MAX];
int length = __system_property_get("ro.build.version.sdk", api_string);
if (length <= 0) {
return -1;
}
int api_level;
bool success =
base::StringToInt(base::StringPiece(api_string, length), &api_level);
return success ? api_level : -1;
}
#endif // OS_ANDROID
void TestAgainstTarget(pid_t pid, bool is_64_bit) {
// Use ElfImageReader on the main executable which can tell us the debug
// address. glibc declares the symbol _r_debug in link.h which we can use to
// get the address, but Android does not.
AuxiliaryVector aux;
ASSERT_TRUE(aux.Initialize(pid, is_64_bit));
LinuxVMAddress phdrs;
ASSERT_TRUE(aux.GetValue(AT_PHDR, &phdrs));
MemoryMap mappings;
ASSERT_TRUE(mappings.Initialize(pid));
const MemoryMap::Mapping* phdr_mapping = mappings.FindMapping(phdrs);
ASSERT_TRUE(phdr_mapping);
const MemoryMap::Mapping* exe_mapping =
mappings.FindFileMmapStart(*phdr_mapping);
LinuxVMAddress elf_address = exe_mapping->range.Base();
ProcessMemory memory;
ASSERT_TRUE(memory.Initialize(pid));
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
ElfImageReader exe_reader;
ASSERT_TRUE(exe_reader.Initialize(range, elf_address));
LinuxVMAddress debug_address;
ASSERT_TRUE(exe_reader.GetDebugAddress(&debug_address));
// start the actual tests
DebugRendezvous debug;
ASSERT_TRUE(debug.Initialize(range, debug_address));
#if defined(OS_ANDROID)
const int android_runtime_api = AndroidRuntimeAPI();
ASSERT_GE(android_runtime_api, 1);
EXPECT_NE(debug.Executable()->name.find("crashpad_snapshot_test"),
std::string::npos);
// Android's loader never sets the dynamic array for the executable.
EXPECT_EQ(debug.Executable()->dynamic_array, 0u);
#else
// glibc's loader implements most of the tested features that Android's was
// missing but has since gained.
const int android_runtime_api = std::numeric_limits<int>::max();
// glibc's loader does not set the name for the executable.
EXPECT_TRUE(debug.Executable()->name.empty());
CheckedLinuxAddressRange exe_range(
is_64_bit, exe_reader.Address(), exe_reader.Size());
EXPECT_TRUE(exe_range.ContainsValue(debug.Executable()->dynamic_array));
#endif // OS_ANDROID
// Android's loader doesn't set the load bias until Android 4.3 (API 18).
if (android_runtime_api >= 18) {
EXPECT_EQ(debug.Executable()->load_bias, exe_reader.GetLoadBias());
} else {
EXPECT_EQ(debug.Executable()->load_bias, 0);
}
for (const DebugRendezvous::LinkEntry& module : debug.Modules()) {
SCOPED_TRACE(base::StringPrintf("name %s, load_bias 0x%" PRIx64
", dynamic_array 0x%" PRIx64,
module.name.c_str(),
module.load_bias,
module.dynamic_array));
const bool is_android_loader = (module.name == "/system/bin/linker" ||
module.name == "/system/bin/linker64");
// Android's loader doesn't set its own dynamic array until Android 4.2
// (API 17).
if (is_android_loader && android_runtime_api < 17) {
EXPECT_EQ(module.dynamic_array, 0u);
EXPECT_EQ(module.load_bias, 0);
continue;
}
ASSERT_TRUE(module.dynamic_array);
const MemoryMap::Mapping* dyn_mapping =
mappings.FindMapping(module.dynamic_array);
ASSERT_TRUE(dyn_mapping);
const MemoryMap::Mapping* module_mapping =
mappings.FindFileMmapStart(*dyn_mapping);
ASSERT_TRUE(module_mapping);
#if defined(OS_ANDROID)
EXPECT_FALSE(module.name.empty());
#else
// glibc's loader doesn't set the name in the link map for the vdso.
EXPECT_PRED4(
[](const std::string mapping_name,
int device,
int inode,
const std::string& module_name) {
return module_name.empty() ==
(device == 0 && inode == 0 && mapping_name == "[vdso]");
},
module_mapping->name,
module_mapping->device,
module_mapping->inode,
module.name);
#endif // OS_ANDROID
ElfImageReader module_reader;
ASSERT_TRUE(module_reader.Initialize(range, module_mapping->range.Base()));
// Android's loader stops setting its own load bias after Android 4.4.4
// (API 20) until Android 6.0 (API 23).
if (is_android_loader && android_runtime_api > 20 &&
android_runtime_api < 23) {
EXPECT_EQ(module.load_bias, 0);
} else {
EXPECT_EQ(module.load_bias, module_reader.GetLoadBias());
}
CheckedLinuxAddressRange module_range(
is_64_bit, module_reader.Address(), module_reader.Size());
EXPECT_TRUE(module_range.ContainsValue(module.dynamic_array));
}
}
TEST(DebugRendezvous, Self) {
#if defined(ARCH_CPU_64_BITS)
constexpr bool is_64_bit = true;
#else
constexpr bool is_64_bit = false;
#endif
TestAgainstTarget(getpid(), is_64_bit);
}
class ChildTest : public Multiprocess {
public:
ChildTest() {}
~ChildTest() {}
private:
void MultiprocessParent() {
#if defined(ARCH_CPU_64_BITS)
constexpr bool is_64_bit = true;
#else
constexpr bool is_64_bit = false;
#endif
TestAgainstTarget(ChildPID(), is_64_bit);
}
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
DISALLOW_COPY_AND_ASSIGN(ChildTest);
};
TEST(DebugRendezvous, Child) {
ChildTest test;
test.Run();
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,75 @@
// Copyright 2017 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 "snapshot/linux/elf_dynamic_array_reader.h"
#include <elf.h>
#include "util/stdlib/map_insert.h"
namespace crashpad {
namespace {
template <typename DynType>
bool Read(const ProcessMemoryRange& memory,
LinuxVMAddress address,
LinuxVMSize size,
std::map<uint64_t, uint64_t>* values) {
std::map<uint64_t, uint64_t> local_values;
while (size > 0) {
DynType entry;
if (!memory.Read(address, sizeof(entry), &entry)) {
return false;
}
size -= sizeof(entry);
address += sizeof(entry);
switch (entry.d_tag) {
case DT_NULL:
values->swap(local_values);
if (size != 0) {
LOG(WARNING) << size << " trailing bytes not read";
}
return true;
case DT_NEEDED:
// Skip these entries for now.
break;
default:
if (!MapInsertOrReplace(
&local_values, entry.d_tag, entry.d_un.d_val, nullptr)) {
LOG(ERROR) << "duplicate dynamic array entry";
return false;
}
}
}
LOG(ERROR) << "missing DT_NULL";
return false;
}
} // namespace
ElfDynamicArrayReader::ElfDynamicArrayReader() : values_() {}
ElfDynamicArrayReader::~ElfDynamicArrayReader() {}
bool ElfDynamicArrayReader::Initialize(const ProcessMemoryRange& memory,
LinuxVMAddress address,
LinuxVMSize size) {
return memory.Is64Bit() ? Read<Elf64_Dyn>(memory, address, size, &values_)
: Read<Elf32_Dyn>(memory, address, size, &values_);
}
} // namespace crashpad

View File

@ -0,0 +1,73 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_
#define CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_
#include <stdint.h>
#include <map>
#include "base/logging.h"
#include "base/macros.h"
#include "util/linux/address_types.h"
#include "util/linux/process_memory_range.h"
#include "util/misc/reinterpret_bytes.h"
namespace crashpad {
//! \brief A reader for ELF dynamic arrays mapped into another process.
class ElfDynamicArrayReader {
public:
ElfDynamicArrayReader();
~ElfDynamicArrayReader();
//! \brief Initializes the reader.
//!
//! This method must be called once on an object and must be successfully
//! called before any other method in this class may be called.
//!
//! \param[in] memory A memory reader for the remote process.
//! \param[in] address The address in the remote process' address space where
//! the ELF dynamic table is loaded.
//! \param[in] size The maximum number of bytes to read.
bool Initialize(const ProcessMemoryRange& memory,
LinuxVMAddress address,
LinuxVMSize size);
//! \brief Retrieve a value from the array.
//!
//! \param[in] tag Specifies which value should be retrieved. The possible
//! values for this parameter are the `DT_*` values from `<elf.h>`.
//! \param[out] value The value, casted to an appropriate type, if found.
//! \return `true` if the value is found.
template <typename V>
bool GetValue(uint64_t tag, V* value) {
auto iter = values_.find(tag);
if (iter == values_.end()) {
LOG(ERROR) << "tag not found";
return false;
}
return ReinterpretBytes(iter->second, value);
}
private:
std::map<uint64_t, uint64_t> values_;
DISALLOW_COPY_AND_ASSIGN(ElfDynamicArrayReader);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_DYNAMIC_ARRAY_READER_H_

View File

@ -0,0 +1,471 @@
// Copyright 2017 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 "snapshot/linux/elf_image_reader.h"
#include <stddef.h>
#include <limits>
#include <vector>
#include "base/logging.h"
#include "build/build_config.h"
namespace crashpad {
class ElfImageReader::ProgramHeaderTable {
public:
virtual ~ProgramHeaderTable() {}
virtual bool VerifyLoadSegments() const = 0;
virtual size_t Size() const = 0;
virtual bool GetDynamicSegment(LinuxVMAddress* address,
LinuxVMSize* size) const = 0;
virtual bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const = 0;
virtual bool GetPreferredLoadedMemoryRange(LinuxVMAddress* address,
LinuxVMSize* size) const = 0;
protected:
ProgramHeaderTable() {}
};
template <typename PhdrType>
class ElfImageReader::ProgramHeaderTableSpecific
: public ElfImageReader::ProgramHeaderTable {
public:
ProgramHeaderTableSpecific<PhdrType>() {}
~ProgramHeaderTableSpecific<PhdrType>() {}
bool Initialize(const ProcessMemoryRange& memory,
LinuxVMAddress address,
LinuxVMSize num_segments) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
table_.resize(num_segments);
if (!memory.Read(address, sizeof(PhdrType) * num_segments, table_.data())) {
return false;
}
if (!VerifyLoadSegments()) {
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
bool VerifyLoadSegments() const override {
constexpr bool is_64_bit = std::is_same<PhdrType, Elf64_Phdr>::value;
LinuxVMAddress last_vaddr;
bool load_found = false;
for (const auto& header : table_) {
if (header.p_type == PT_LOAD) {
CheckedLinuxAddressRange load_range(
is_64_bit, header.p_vaddr, header.p_memsz);
if (!load_range.IsValid()) {
LOG(ERROR) << "bad load range";
return false;
}
if (load_found && header.p_vaddr <= last_vaddr) {
LOG(ERROR) << "out of order load segments";
return false;
}
load_found = true;
last_vaddr = header.p_vaddr;
}
}
return true;
}
size_t Size() const override { return sizeof(PhdrType) * table_.size(); }
bool GetPreferredElfHeaderAddress(LinuxVMAddress* address) const override {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
for (const auto& header : table_) {
if (header.p_type == PT_LOAD && header.p_offset == 0) {
*address = header.p_vaddr;
return true;
}
}
LOG(ERROR) << "no preferred header address";
return false;
}
bool GetPreferredLoadedMemoryRange(LinuxVMAddress* base,
LinuxVMSize* size) const override {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
LinuxVMAddress preferred_base = 0;
LinuxVMAddress preferred_end = 0;
bool load_found = false;
for (const auto& header : table_) {
if (header.p_type == PT_LOAD) {
if (!load_found) {
preferred_base = header.p_vaddr;
load_found = true;
}
preferred_end = header.p_vaddr + header.p_memsz;
}
}
if (load_found) {
*base = preferred_base;
*size = preferred_end - preferred_base;
return true;
}
LOG(ERROR) << "no load segments";
return false;
}
bool GetDynamicSegment(LinuxVMAddress* address,
LinuxVMSize* size) const override {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
const PhdrType* phdr;
if (!GetProgramHeader(PT_DYNAMIC, &phdr)) {
return false;
}
*address = phdr->p_vaddr;
*size = phdr->p_memsz;
return true;
}
bool GetProgramHeader(uint32_t type, const PhdrType** header_out) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
for (const auto& header : table_) {
if (header.p_type == type) {
*header_out = &header;
return true;
}
}
return false;
}
private:
std::vector<PhdrType> table_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProgramHeaderTableSpecific<PhdrType>);
};
ElfImageReader::ElfImageReader()
: header_64_(),
ehdr_address_(0),
load_bias_(0),
memory_(),
program_headers_(),
dynamic_array_(),
symbol_table_(),
initialized_(),
dynamic_array_initialized_(),
symbol_table_initialized_() {}
ElfImageReader::~ElfImageReader() {}
bool ElfImageReader::Initialize(const ProcessMemoryRange& memory,
LinuxVMAddress address) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
ehdr_address_ = address;
if (!memory_.Initialize(memory)) {
return false;
}
uint8_t e_ident[EI_NIDENT];
if (!memory_.Read(ehdr_address_, EI_NIDENT, e_ident)) {
return false;
}
if (e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 ||
e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3) {
LOG(ERROR) << "Incorrect ELF magic number";
return false;
}
if (!(memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS64) &&
!(!memory_.Is64Bit() && e_ident[EI_CLASS] == ELFCLASS32)) {
LOG(ERROR) << "unexpected bitness";
return false;
}
#if defined(ARCH_CPU_LITTLE_ENDIAN)
constexpr uint8_t expected_encoding = ELFDATA2LSB;
#elif defined(ARCH_CPU_BIG_ENDIAN)
constexpr uint8_t expected_encoding = ELFDATA2MSB;
#endif
if (e_ident[EI_DATA] != expected_encoding) {
LOG(ERROR) << "unexpected encoding";
return false;
}
if (e_ident[EI_VERSION] != EV_CURRENT) {
LOG(ERROR) << "unexpected version";
return false;
}
if (!(memory_.Is64Bit()
? memory_.Read(ehdr_address_, sizeof(header_64_), &header_64_)
: memory_.Read(ehdr_address_, sizeof(header_32_), &header_32_))) {
return false;
}
#define VERIFY_HEADER(header) \
do { \
if (header.e_type != ET_EXEC && header.e_type != ET_DYN) { \
LOG(ERROR) << "unexpected image type"; \
return false; \
} \
if (header.e_version != EV_CURRENT) { \
LOG(ERROR) << "unexpected version"; \
return false; \
} \
if (header.e_ehsize != sizeof(header)) { \
LOG(ERROR) << "unexpected header size"; \
return false; \
} \
} while (false);
if (memory_.Is64Bit()) {
VERIFY_HEADER(header_64_);
} else {
VERIFY_HEADER(header_32_);
}
if (!InitializeProgramHeaders()) {
return false;
}
LinuxVMAddress preferred_ehdr_address;
if (!program_headers_.get()->GetPreferredElfHeaderAddress(
&preferred_ehdr_address)) {
return false;
}
load_bias_ = ehdr_address_ - preferred_ehdr_address;
LinuxVMAddress base_address;
LinuxVMSize loaded_size;
if (!program_headers_.get()->GetPreferredLoadedMemoryRange(&base_address,
&loaded_size)) {
return false;
}
base_address += load_bias_;
if (!memory_.RestrictRange(base_address, loaded_size)) {
return false;
}
LinuxVMSize ehdr_size;
LinuxVMAddress phdr_address;
if (memory_.Is64Bit()) {
ehdr_size = sizeof(header_64_);
phdr_address = ehdr_address_ + header_64_.e_phoff;
} else {
ehdr_size = sizeof(header_32_);
phdr_address = ehdr_address_ + header_32_.e_phoff;
}
CheckedLinuxAddressRange range(memory_.Is64Bit(), base_address, loaded_size);
if (!range.ContainsRange(CheckedLinuxAddressRange(
memory_.Is64Bit(), ehdr_address_, ehdr_size))) {
LOG(ERROR) << "ehdr out of range";
return false;
}
if (!range.ContainsRange(CheckedLinuxAddressRange(
memory.Is64Bit(), phdr_address, program_headers_->Size()))) {
LOG(ERROR) << "phdrs out of range";
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
uint16_t ElfImageReader::FileType() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return memory_.Is64Bit() ? header_64_.e_type : header_32_.e_type;
}
bool ElfImageReader::GetDynamicSymbol(const std::string& name,
LinuxVMAddress* address,
LinuxVMSize* size) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!InitializeDynamicSymbolTable()) {
return false;
}
ElfSymbolTableReader::SymbolInformation info;
if (!symbol_table_->GetSymbol(name, &info)) {
return false;
}
if (info.shndx == SHN_UNDEF || info.shndx == SHN_COMMON) {
return false;
}
switch (info.binding) {
case STB_GLOBAL:
case STB_WEAK:
break;
case STB_LOCAL:
default:
return false;
}
switch (info.type) {
case STT_OBJECT:
case STT_FUNC:
break;
case STT_COMMON:
case STT_NOTYPE:
case STT_SECTION:
case STT_FILE:
case STT_TLS:
default:
return false;
}
if (info.shndx != SHN_ABS) {
info.address += GetLoadBias();
}
*address = info.address;
*size = info.size;
return true;
}
bool ElfImageReader::ReadDynamicStringTableAtOffset(LinuxVMSize offset,
std::string* string) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!InitializeDynamicArray()) {
return false;
}
LinuxVMAddress string_table_address;
LinuxVMSize string_table_size;
if (!GetAddressFromDynamicArray(DT_STRTAB, &string_table_address) ||
!dynamic_array_->GetValue(DT_STRSZ, &string_table_size)) {
LOG(ERROR) << "missing string table info";
return false;
}
if (offset >= string_table_size) {
LOG(ERROR) << "bad offset";
return false;
}
if (!memory_.ReadCStringSizeLimited(
string_table_address + offset, string_table_size - offset, string)) {
LOG(ERROR) << "missing nul-terminator";
return false;
}
return true;
}
bool ElfImageReader::GetDebugAddress(LinuxVMAddress* debug) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!InitializeDynamicArray()) {
return false;
}
return GetAddressFromDynamicArray(DT_DEBUG, debug);
}
bool ElfImageReader::InitializeProgramHeaders() {
#define INITIALIZE_PROGRAM_HEADERS(PhdrType, header) \
do { \
if (header.e_phentsize != sizeof(PhdrType)) { \
LOG(ERROR) << "unexpected phdr size"; \
return false; \
} \
auto phdrs = new ProgramHeaderTableSpecific<PhdrType>(); \
program_headers_.reset(phdrs); \
if (!phdrs->Initialize( \
memory_, ehdr_address_ + header.e_phoff, header.e_phnum)) { \
return false; \
} \
} while (false);
if (memory_.Is64Bit()) {
INITIALIZE_PROGRAM_HEADERS(Elf64_Phdr, header_64_);
} else {
INITIALIZE_PROGRAM_HEADERS(Elf32_Phdr, header_32_);
}
return true;
}
bool ElfImageReader::InitializeDynamicArray() {
if (dynamic_array_initialized_.is_valid()) {
return true;
}
if (!dynamic_array_initialized_.is_uninitialized()) {
return false;
}
dynamic_array_initialized_.set_invalid();
LinuxVMAddress dyn_segment_address;
LinuxVMSize dyn_segment_size;
if (!program_headers_.get()->GetDynamicSegment(&dyn_segment_address,
&dyn_segment_size)) {
LOG(ERROR) << "no dynamic segment";
return false;
}
dyn_segment_address += GetLoadBias();
dynamic_array_.reset(new ElfDynamicArrayReader());
if (!dynamic_array_->Initialize(
memory_, dyn_segment_address, dyn_segment_size)) {
return false;
}
dynamic_array_initialized_.set_valid();
return true;
}
bool ElfImageReader::InitializeDynamicSymbolTable() {
if (symbol_table_initialized_.is_valid()) {
return true;
}
if (!symbol_table_initialized_.is_uninitialized()) {
return false;
}
symbol_table_initialized_.set_invalid();
if (!InitializeDynamicArray()) {
return false;
}
LinuxVMAddress symbol_table_address;
if (!GetAddressFromDynamicArray(DT_SYMTAB, &symbol_table_address)) {
LOG(ERROR) << "no symbol table";
return false;
}
symbol_table_.reset(
new ElfSymbolTableReader(&memory_, this, symbol_table_address));
symbol_table_initialized_.set_valid();
return true;
}
bool ElfImageReader::GetAddressFromDynamicArray(uint64_t tag,
LinuxVMAddress* address) {
if (!dynamic_array_->GetValue(tag, address)) {
return false;
}
#if defined(OS_ANDROID)
// The GNU loader updates the dynamic array according to the load bias while
// the Android loader only updates the debug address.
if (tag != DT_DEBUG) {
*address += GetLoadBias();
}
#endif // OS_ANDROID
return true;
}
} // namespace crashpad

View File

@ -0,0 +1,133 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_
#define CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_
#include <elf.h>
#include <stdint.h>
#include <memory>
#include <string>
#include "base/macros.h"
#include "util/linux/address_types.h"
#include "snapshot/linux/elf_dynamic_array_reader.h"
#include "snapshot/linux/elf_symbol_table_reader.h"
#include "util/linux/process_memory_range.h"
#include "util/misc/initialization_state.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
//! \brief A reader for ELF images mapped into another process.
//!
//! This class is capable of reading both 32-bit and 64-bit images.
class ElfImageReader {
public:
ElfImageReader();
~ElfImageReader();
//! \brief Initializes the reader.
//!
//! This method must be called once on an object and must be successfully
//! called before any other method in this class may be called.
//!
//! \param[in] memory A memory reader for the remote process.
//! \param[in] address The address in the remote process' address space where
//! the ELF image is loaded.
bool Initialize(const ProcessMemoryRange& memory, LinuxVMAddress address);
//! \brief Returns the base address of the image's memory range.
//!
//! This may differ from the address passed to Initialize() if the ELF header
//! is not loaded at the start of the first `PT_LOAD` segment.
LinuxVMAddress Address() const { return memory_.Base(); }
//! \brief Returns the size of the range containing all loaded segments for
//! this image.
//!
//! The size may include memory that is unmapped or mapped to other objects if
//! this image's `PT_LOAD` segments are not contiguous.
LinuxVMSize Size() const { return memory_.Size(); }
//! \brief Returns the file type for the image.
//!
//! Possible values include `ET_EXEC` or `ET_DYN` from `<elf.h>`.
uint16_t FileType() const;
//! \brief Returns the load bias for the image.
//!
//! The load bias is the actual load address minus the preferred load address.
LinuxVMOffset GetLoadBias() const { return load_bias_; }
//! \brief Reads information from the dynamic symbol table about the symbol
//! identified by \a name.
//!
//! \param[in] name The name of the symbol to search for.
//! \param[out] address The address of the symbol in the target process'
//! address space, if found.
//! \param[out] size The size of the symbol, if found.
//! \return `true` if the symbol was found.
bool GetDynamicSymbol(const std::string& name,
LinuxVMAddress* address,
LinuxVMSize* size);
//! \brief Reads a `NUL`-terminated C string from this image's dynamic string
//! table.
//!
//! \param[in] offset the byte offset in the string table to start reading.
//! \param[out] string the string read.
//! \return `true` on success. Otherwise `false` with a message logged.
bool ReadDynamicStringTableAtOffset(LinuxVMSize offset, std::string* string);
//! \brief Determine the debug address.
//!
//! The debug address is a pointer to an `r_debug` struct defined in
//! `<link.h>`.
//!
//! \param[out] debug the debug address, if found.
//! \return `true` if the debug address was found.
bool GetDebugAddress(LinuxVMAddress* debug);
private:
class ProgramHeaderTable;
template <typename PhdrType>
class ProgramHeaderTableSpecific;
bool InitializeProgramHeaders();
bool InitializeDynamicArray();
bool InitializeDynamicSymbolTable();
bool GetAddressFromDynamicArray(uint64_t tag, LinuxVMAddress* address);
union {
Elf32_Ehdr header_32_;
Elf64_Ehdr header_64_;
};
LinuxVMAddress ehdr_address_;
LinuxVMOffset load_bias_;
ProcessMemoryRange memory_;
std::unique_ptr<ProgramHeaderTable> program_headers_;
std::unique_ptr<ElfDynamicArrayReader> dynamic_array_;
std::unique_ptr<ElfSymbolTableReader> symbol_table_;
InitializationStateDcheck initialized_;
InitializationState dynamic_array_initialized_;
InitializationState symbol_table_initialized_;
DISALLOW_COPY_AND_ASSIGN(ElfImageReader);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_IMAGE_READER_H_

View File

@ -0,0 +1,157 @@
// Copyright 2017 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 "snapshot/linux/elf_image_reader.h"
#include <dlfcn.h>
#include <unistd.h>
#include "base/logging.h"
#include "gtest/gtest.h"
#include "test/multiprocess.h"
#include "util/file/file_io.h"
#include "util/linux/address_types.h"
#include "util/linux/auxiliary_vector.h"
#include "util/linux/memory_map.h"
#include "util/misc/from_pointer_cast.h"
extern "C" {
__attribute__((visibility("default"))) void
ElfImageReaderTestExportedSymbol(){};
} // extern "C"
namespace crashpad {
namespace test {
namespace {
void LocateExecutable(pid_t pid, bool is_64_bit, LinuxVMAddress* elf_address) {
AuxiliaryVector aux;
ASSERT_TRUE(aux.Initialize(pid, is_64_bit));
LinuxVMAddress phdrs;
ASSERT_TRUE(aux.GetValue(AT_PHDR, &phdrs));
MemoryMap memory_map;
ASSERT_TRUE(memory_map.Initialize(pid));
const MemoryMap::Mapping* phdr_mapping = memory_map.FindMapping(phdrs);
ASSERT_TRUE(phdr_mapping);
const MemoryMap::Mapping* exe_mapping =
memory_map.FindFileMmapStart(*phdr_mapping);
ASSERT_TRUE(exe_mapping);
*elf_address = exe_mapping->range.Base();
}
void ExpectElfImageWithSymbol(pid_t pid,
LinuxVMAddress address,
bool is_64_bit,
std::string symbol_name,
LinuxVMAddress expected_symbol_address) {
ProcessMemory memory;
ASSERT_TRUE(memory.Initialize(pid));
ProcessMemoryRange range;
ASSERT_TRUE(range.Initialize(&memory, is_64_bit));
ElfImageReader reader;
ASSERT_TRUE(reader.Initialize(range, address));
LinuxVMAddress symbol_address;
LinuxVMSize symbol_size;
ASSERT_TRUE(
reader.GetDynamicSymbol(symbol_name, &symbol_address, &symbol_size));
EXPECT_EQ(symbol_address, expected_symbol_address);
EXPECT_FALSE(
reader.GetDynamicSymbol("notasymbol", &symbol_address, &symbol_size));
}
void ReadThisExecutableInTarget(pid_t pid) {
#if defined(ARCH_CPU_64_BITS)
constexpr bool am_64_bit = true;
#else
constexpr bool am_64_bit = false;
#endif // ARCH_CPU_64_BITS
LinuxVMAddress elf_address;
LocateExecutable(pid, am_64_bit, &elf_address);
ExpectElfImageWithSymbol(
pid,
elf_address,
am_64_bit,
"ElfImageReaderTestExportedSymbol",
FromPointerCast<LinuxVMAddress>(ElfImageReaderTestExportedSymbol));
}
// Assumes that libc is loaded at the same address in this process as in the
// target, which it is for the fork test below.
void ReadLibcInTarget(pid_t pid) {
#if defined(ARCH_CPU_64_BITS)
constexpr bool am_64_bit = true;
#else
constexpr bool am_64_bit = false;
#endif // ARCH_CPU_64_BITS
Dl_info info;
ASSERT_TRUE(dladdr(reinterpret_cast<void*>(getpid), &info)) << "dladdr:"
<< dlerror();
LinuxVMAddress elf_address = FromPointerCast<LinuxVMAddress>(info.dli_fbase);
ExpectElfImageWithSymbol(pid,
elf_address,
am_64_bit,
"getpid",
FromPointerCast<LinuxVMAddress>(getpid));
}
class ReadExecutableChildTest : public Multiprocess {
public:
ReadExecutableChildTest() : Multiprocess() {}
~ReadExecutableChildTest() {}
private:
void MultiprocessParent() { ReadThisExecutableInTarget(ChildPID()); }
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
};
TEST(ElfImageReader, MainExecutableSelf) {
ReadThisExecutableInTarget(getpid());
}
TEST(ElfImageReader, MainExecutableChild) {
ReadExecutableChildTest test;
test.Run();
}
TEST(ElfImageReader, OneModuleSelf) {
ReadLibcInTarget(getpid());
}
class ReadLibcChildTest : public Multiprocess {
public:
ReadLibcChildTest() : Multiprocess() {}
~ReadLibcChildTest() {}
private:
void MultiprocessParent() { ReadLibcInTarget(ChildPID()); }
void MultiprocessChild() { CheckedReadFileAtEOF(ReadPipeHandle()); }
};
TEST(ElfImageReader, OneModuleChild) {
ReadLibcChildTest test;
test.Run();
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,87 @@
// Copyright 2017 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 "snapshot/linux/elf_symbol_table_reader.h"
#include <elf.h>
#include "base/logging.h"
#include "snapshot/linux/elf_image_reader.h"
namespace crashpad {
namespace {
uint8_t GetBinding(const Elf32_Sym& sym) {
return ELF32_ST_BIND(sym.st_info);
}
uint8_t GetBinding(const Elf64_Sym& sym) {
return ELF64_ST_BIND(sym.st_info);
}
uint8_t GetType(const Elf32_Sym& sym) {
return ELF32_ST_TYPE(sym.st_info);
}
uint8_t GetType(const Elf64_Sym& sym) {
return ELF64_ST_TYPE(sym.st_info);
}
uint8_t GetVisibility(const Elf32_Sym& sym) {
return ELF32_ST_VISIBILITY(sym.st_other);
}
uint8_t GetVisibility(const Elf64_Sym& sym) {
return ELF64_ST_VISIBILITY(sym.st_other);
}
} // namespace
ElfSymbolTableReader::ElfSymbolTableReader(const ProcessMemoryRange* memory,
ElfImageReader* elf_reader,
LinuxVMAddress address)
: memory_(memory), elf_reader_(elf_reader), base_address_(address) {}
ElfSymbolTableReader::~ElfSymbolTableReader() {}
bool ElfSymbolTableReader::GetSymbol(const std::string& name,
SymbolInformation* info) {
return memory_->Is64Bit() ? ScanSymbolTable<Elf64_Sym>(name, info)
: ScanSymbolTable<Elf32_Sym>(name, info);
}
template <typename SymEnt>
bool ElfSymbolTableReader::ScanSymbolTable(const std::string& name,
SymbolInformation* info_out) {
LinuxVMAddress address = base_address_;
SymEnt entry;
std::string string;
while (memory_->Read(address, sizeof(entry), &entry) &&
elf_reader_->ReadDynamicStringTableAtOffset(entry.st_name, &string)) {
if (string == name) {
info_out->address = entry.st_value;
info_out->size = entry.st_size;
info_out->shndx = entry.st_shndx;
info_out->binding = GetBinding(entry);
info_out->type = GetType(entry);
info_out->visibility = GetVisibility(entry);
return true;
}
address += sizeof(entry);
}
return false;
}
} // namespace crashpad

View File

@ -0,0 +1,87 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_
#define CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_
#include <stdint.h>
#include <string>
#include "base/macros.h"
#include "util/linux/address_types.h"
#include "util/linux/process_memory_range.h"
namespace crashpad {
class ElfImageReader;
//! \brief A reader for symbol tables in ELF images mapped into another process.
class ElfSymbolTableReader {
public:
//! \brief Information about a symbol in a module's symbol table.
struct SymbolInformation {
//! \brief The address of the symbol as it exists in the symbol table, not
//! adjusted for any load bias.
LinuxVMAddress address;
//! \brief The size of the symbol.
LinuxVMSize size;
//! \brief The section index that the symbol definition is in relation to.
uint16_t shndx;
//! \brief Specifies the type of symbol. Possible values include
//! `STT_OBJECT`, `STT_FUNC`, etc.
uint8_t type;
//! \brief Specifies the default scope at which a symbol takes precedence.
//! Possible values include `STB_LOCAL`, `STB_GLOBAL`, `STB_WEAK`, or
//! OS/processor specific values.
uint8_t binding;
//! \brief Together with binding, can limit the visibility of a symbol to
//! the module that defines it. Possible values include `STV_DEFAULT`,
//! `STV_INTERNAL`, `STV_HIDDEN`, and `STV_PROTECTED`.
uint8_t visibility;
};
// TODO(jperaza): Support using .hash and .gnu.hash sections to improve symbol
// lookup.
ElfSymbolTableReader(const ProcessMemoryRange* memory,
ElfImageReader* elf_reader,
LinuxVMAddress address);
~ElfSymbolTableReader();
//! \brief Lookup information about a symbol.
//!
//! \param[in] name The name of the symbol to search for.
//! \param[out] info The symbol information, if found.
//! \return `true` if the symbol is found.
bool GetSymbol(const std::string& name, SymbolInformation* info);
private:
template <typename SymEnt>
bool ScanSymbolTable(const std::string& name, SymbolInformation* info);
const ProcessMemoryRange* const memory_; // weak
ElfImageReader* const elf_reader_; // weak
const LinuxVMAddress base_address_;
DISALLOW_COPY_AND_ASSIGN(ElfSymbolTableReader);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_ELF_SYMBOL_TABLE_READER_H_

View File

@ -0,0 +1,68 @@
// Copyright 2017 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 "snapshot/linux/memory_snapshot_linux.h"
#include <memory>
namespace crashpad {
namespace internal {
MemorySnapshotLinux::MemorySnapshotLinux()
: MemorySnapshot(),
process_reader_(nullptr),
address_(0),
size_(0),
initialized_() {
}
MemorySnapshotLinux::~MemorySnapshotLinux() {
}
void MemorySnapshotLinux::Initialize(ProcessReader* process_reader,
LinuxVMAddress address,
size_t size) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
process_reader_ = process_reader;
address_ = address;
size_ = size;
INITIALIZATION_STATE_SET_VALID(initialized_);
}
uint64_t MemorySnapshotLinux::Address() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return address_;
}
size_t MemorySnapshotLinux::Size() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return size_;
}
bool MemorySnapshotLinux::Read(Delegate* delegate) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (size_ == 0) {
return delegate->MemorySnapshotDelegateRead(nullptr, size_);
}
std::unique_ptr<uint8_t[]> buffer(new uint8_t[size_]);
if (!process_reader_->Memory()->Read(address_, size_, buffer.get())) {
return false;
}
return delegate->MemorySnapshotDelegateRead(buffer.get(), size_);
}
} // namespace internal
} // namespace crashpad

View File

@ -0,0 +1,69 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_
#define CRASHPAD_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_
#include <stddef.h>
#include <stdint.h>
#include "base/macros.h"
#include "snapshot/linux/process_reader.h"
#include "snapshot/memory_snapshot.h"
#include "util/linux/address_types.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
namespace internal {
//! \brief A MemorySnapshot of a memory region in a process on the running
//! system, when the system runs Linux.
class MemorySnapshotLinux final : public MemorySnapshot {
public:
MemorySnapshotLinux();
~MemorySnapshotLinux() override;
//! \brief Initializes the object.
//!
//! Memory is read lazily. No attempt is made to read the memory snapshot data
//! until Read() is called, and the memory snapshot data is discared when
//! Read() returns.
//!
//! \param[in] process_reader A reader for the process being snapshotted.
//! \param[in] address The base address of the memory region to snapshot, in
//! the snapshot process address space.
//! \param[in] size The size of the memory region to snapshot.
void Initialize(ProcessReader* process_reader,
LinuxVMAddress address,
size_t size);
// MemorySnapshot:
uint64_t Address() const override;
size_t Size() const override;
bool Read(Delegate* delegate) const override;
private:
ProcessReader* process_reader_; // weak
uint64_t address_;
size_t size_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(MemorySnapshotLinux);
};
} // namespace internal
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_MEMORY_SNAPSHOT_LINUX_H_

View File

@ -0,0 +1,322 @@
// Copyright 2017 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 "snapshot/linux/process_reader.h"
#include <dirent.h>
#include <errno.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <algorithm>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "util/linux/proc_stat_reader.h"
#include "util/posix/scoped_dir.h"
namespace crashpad {
namespace {
bool ShouldMergeStackMappings(const MemoryMap::Mapping& stack_mapping,
const MemoryMap::Mapping& adj_mapping) {
DCHECK(stack_mapping.readable);
return adj_mapping.readable && stack_mapping.device == adj_mapping.device &&
stack_mapping.inode == adj_mapping.inode;
}
} // namespace
ProcessReader::Thread::Thread()
: thread_context(),
float_context(),
thread_specific_data_address(0),
stack_region_address(0),
stack_region_size(0),
tid(-1),
static_priority(-1),
nice_value(-1) {}
ProcessReader::Thread::~Thread() {}
bool ProcessReader::Thread::InitializePtrace() {
ThreadInfo thread_info;
if (!thread_info.Initialize(tid)) {
return false;
}
thread_info.GetGeneralPurposeRegisters(&thread_context);
if (!thread_info.GetFloatingPointRegisters(&float_context)) {
return false;
}
if (!thread_info.GetThreadArea(&thread_specific_data_address)) {
return false;
}
// TODO(jperaza): Starting with Linux 3.14, scheduling policy, static
// priority, and nice value can be collected all in one call with
// sched_getattr().
int res = sched_getscheduler(tid);
if (res < 0) {
PLOG(ERROR) << "sched_getscheduler";
return false;
}
sched_policy = res;
sched_param param;
if (sched_getparam(tid, &param) != 0) {
PLOG(ERROR) << "sched_getparam";
return false;
}
static_priority = param.sched_priority;
errno = 0;
res = getpriority(PRIO_PROCESS, tid);
if (res == -1 && errno) {
PLOG(ERROR) << "getpriority";
return false;
}
nice_value = res;
return true;
}
void ProcessReader::Thread::InitializeStack(ProcessReader* reader) {
LinuxVMAddress stack_pointer;
#if defined(ARCH_CPU_X86_FAMILY)
stack_pointer =
reader->Is64Bit() ? thread_context.t64.rsp : thread_context.t32.esp;
#elif defined(ARCH_CPU_ARM_FAMILY)
stack_pointer =
reader->Is64Bit() ? thread_context.t64.sp : thread_context.t32.sp;
#else
#error Port.
#endif
const MemoryMap* memory_map = reader->GetMemoryMap();
// If we can't find the mapping, it's probably a bad stack pointer
const MemoryMap::Mapping* mapping = memory_map->FindMapping(stack_pointer);
if (!mapping) {
LOG(WARNING) << "no stack mapping";
return;
}
LinuxVMAddress stack_region_start = stack_pointer;
// We've hit what looks like a guard page; skip to the end and check for a
// mapped stack region.
if (!mapping->readable) {
stack_region_start = mapping->range.End();
mapping = memory_map->FindMapping(stack_region_start);
if (!mapping) {
LOG(WARNING) << "no stack mapping";
return;
}
} else {
#if defined(ARCH_CPU_X86_FAMILY)
// Adjust start address to include the red zone
if (reader->Is64Bit()) {
constexpr LinuxVMSize kRedZoneSize = 128;
LinuxVMAddress red_zone_base =
stack_region_start - std::min(kRedZoneSize, stack_region_start);
// Only include the red zone if it is part of a valid mapping
if (red_zone_base >= mapping->range.Base()) {
stack_region_start = red_zone_base;
} else {
const MemoryMap::Mapping* rz_mapping =
memory_map->FindMapping(red_zone_base);
if (rz_mapping && ShouldMergeStackMappings(*mapping, *rz_mapping)) {
stack_region_start = red_zone_base;
} else {
stack_region_start = mapping->range.Base();
}
}
}
#endif
}
stack_region_address = stack_region_start;
// If there are more mappings at the end of this one, they may be a
// continuation of the stack.
LinuxVMAddress stack_end = mapping->range.End();
const MemoryMap::Mapping* next_mapping;
while ((next_mapping = memory_map->FindMapping(stack_end)) &&
ShouldMergeStackMappings(*mapping, *next_mapping)) {
stack_end = next_mapping->range.End();
}
// The main thread should have an entry in the maps file just for its stack,
// so we'll assume the base of the stack is at the end of the region. Other
// threads' stacks may not have their own entries in the maps file if they
// were user-allocated within a larger mapping, but pthreads places the TLS
// at the high-address end of the stack so we can try using that to shrink
// the stack region.
stack_region_size = stack_end - stack_region_address;
if (tid != reader->ProcessID() &&
thread_specific_data_address > stack_region_address &&
thread_specific_data_address < stack_end) {
stack_region_size = thread_specific_data_address - stack_region_address;
}
}
ProcessReader::ProcessReader()
: process_info_(),
memory_map_(),
threads_(),
process_memory_(),
is_64_bit_(false),
initialized_threads_(false),
initialized_() {}
ProcessReader::~ProcessReader() {}
bool ProcessReader::Initialize(pid_t pid) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
if (!process_info_.Initialize(pid)) {
return false;
}
if (!memory_map_.Initialize(pid)) {
return false;
}
process_memory_.reset(new ProcessMemory());
if (!process_memory_->Initialize(pid)) {
return false;
}
if (!process_info_.Is64Bit(&is_64_bit_)) {
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
bool ProcessReader::StartTime(timeval* start_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return process_info_.StartTime(start_time);
}
bool ProcessReader::CPUTimes(timeval* user_time, timeval* system_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
timerclear(user_time);
timerclear(system_time);
timeval local_user_time;
timerclear(&local_user_time);
timeval local_system_time;
timerclear(&local_system_time);
for (const Thread& thread : threads_) {
ProcStatReader stat;
if (!stat.Initialize(thread.tid)) {
return false;
}
timeval thread_user_time;
if (!stat.UserCPUTime(&thread_user_time)) {
return false;
}
timeval thread_system_time;
if (!stat.SystemCPUTime(&thread_system_time)) {
return false;
}
timeradd(&local_user_time, &thread_user_time, &local_user_time);
timeradd(&local_system_time, &thread_system_time, &local_system_time);
}
*user_time = local_user_time;
*system_time = local_system_time;
return true;
}
const std::vector<ProcessReader::Thread>& ProcessReader::Threads() {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (!initialized_threads_) {
InitializeThreads();
}
return threads_;
}
void ProcessReader::InitializeThreads() {
DCHECK(threads_.empty());
pid_t pid = ProcessID();
if (pid == getpid()) {
// TODO(jperaza): ptrace can't be used on threads in the same thread group.
// Using clone to create a new thread in it's own thread group doesn't work
// because glibc doesn't support threads it didn't create via pthreads.
// Fork a new process to snapshot us and copy the data back?
LOG(ERROR) << "not implemented";
return;
}
char path[32];
snprintf(path, arraysize(path), "/proc/%d/task", pid);
DIR* dir = opendir(path);
if (!dir) {
PLOG(ERROR) << "opendir";
return;
}
ScopedDIR scoped_dir(dir);
Thread main_thread;
main_thread.tid = pid;
if (main_thread.InitializePtrace()) {
main_thread.InitializeStack(this);
threads_.push_back(main_thread);
} else {
LOG(WARNING) << "Couldn't initialize main thread.";
}
bool main_thread_found = false;
dirent* dir_entry;
while ((dir_entry = readdir(scoped_dir.get()))) {
if (strncmp(dir_entry->d_name, ".", arraysize(dir_entry->d_name)) == 0 ||
strncmp(dir_entry->d_name, "..", arraysize(dir_entry->d_name)) == 0) {
continue;
}
pid_t tid;
if (!base::StringToInt(dir_entry->d_name, &tid)) {
LOG(ERROR) << "format error";
continue;
}
if (tid == pid) {
DCHECK(!main_thread_found);
main_thread_found = true;
continue;
}
Thread thread;
thread.tid = tid;
if (thread.InitializePtrace()) {
thread.InitializeStack(this);
threads_.push_back(thread);
}
}
DCHECK(main_thread_found);
}
} // namespace crashpad

View File

@ -0,0 +1,127 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_
#define CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_
#include <sys/time.h>
#include <sys/types.h>
#include <memory>
#include <vector>
#include "base/macros.h"
#include "util/linux/address_types.h"
#include "util/linux/memory_map.h"
#include "util/linux/process_memory.h"
#include "util/linux/thread_info.h"
#include "util/posix/process_info.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
//! \brief Accesses information about another process, identified by a process
//! ID.
class ProcessReader {
public:
//! \brief Contains information about a thread that belongs to a process.
struct Thread {
Thread();
~Thread();
ThreadContext thread_context;
FloatContext float_context;
LinuxVMAddress thread_specific_data_address;
LinuxVMAddress stack_region_address;
LinuxVMSize stack_region_size;
pid_t tid;
int sched_policy;
int static_priority;
int nice_value;
private:
friend class ProcessReader;
bool InitializePtrace();
void InitializeStack(ProcessReader* reader);
};
ProcessReader();
~ProcessReader();
//! \brief Initializes this object.
//!
//! This method must be successfully called before calling any other method in
//! this class.
//!
//! \param[in] pid The process ID of the target process.
//! \return `true` on success. `false` on failure with a message logged.
bool Initialize(pid_t pid);
//! \brief Return `true` if the target task is a 64-bit process.
bool Is64Bit() const { return is_64_bit_; }
//! \brief Return the target process' process ID.
pid_t ProcessID() const { return process_info_.ProcessID(); }
//! \brief Return the target process' parent process ID.
pid_t ParentProcessID() const { return process_info_.ParentProcessID(); }
//! \brief Return a memory reader for the target process.
ProcessMemory* Memory() { return process_memory_.get(); }
//! \brief Return a memory map of the target process.
MemoryMap* GetMemoryMap() { return &memory_map_; }
//! \brief Determines the target process start time.
//!
//! \param[out] start_time The time that the process started.
//! \return `true` on success with \a start_time set. Otherwise `false` with a
//! message logged.
bool StartTime(timeval* start_time) const;
//! \brief Determines the target process execution time.
//!
//! \param[out] user_time The amount of time the process has executed code in
//! user mode.
//! \param[out] system_time The amount of time the process has executed code
//! in system mode.
//!
//! \return `true` on success, `false` on failure, with a warning logged. On
//! failure, \a user_time and \a system_time will be set to represent no
//! time spent executing code in user or system mode.
bool CPUTimes(timeval* user_time, timeval* system_time) const;
//! \brief Return a vector of threads that are in the task process. If the
//! main thread is able to be identified and traced, it will be placed at
//! index `0`.
const std::vector<Thread>& Threads();
private:
void InitializeThreads();
ProcessInfo process_info_;
class MemoryMap memory_map_;
std::vector<Thread> threads_;
std::unique_ptr<ProcessMemory> process_memory_;
bool is_64_bit_;
bool initialized_threads_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProcessReader);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_PROCESS_READER_H_

View File

@ -0,0 +1,450 @@
// Copyright 2017 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 "snapshot/linux/process_reader.h"
#include <errno.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <map>
#include <string>
#include "base/format_macros.h"
#include "base/memory/free_deleter.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "gtest/gtest.h"
#include "test/errors.h"
#include "test/multiprocess.h"
#include "util/file/file_io.h"
#include "util/misc/from_pointer_cast.h"
#include "util/stdlib/pointer_container.h"
#include "util/synchronization/semaphore.h"
namespace crashpad {
namespace test {
namespace {
pid_t gettid() {
return syscall(SYS_gettid);
}
LinuxVMAddress GetTLS() {
LinuxVMAddress tls;
#if defined(ARCH_CPU_ARMEL)
// 0xffff0fe0 is the address of the kernel user helper __kuser_get_tls().
auto kuser_get_tls = reinterpret_cast<void* (*)()>(0xffff0fe0);
tls = FromPointerCast<LinuxVMAddress>(kuser_get_tls());
#elif defined(ARCH_CPU_ARM64)
// Linux/aarch64 places the tls address in system register tpidr_el0.
asm("mrs %0, tpidr_el0" : "=r"(tls));
#elif defined(ARCH_CPU_X86)
uint32_t tls_32;
asm("movl %%gs:0x0, %0" : "=r"(tls_32));
tls = tls_32;
#elif defined(ARCH_CPU_X86_64)
asm("movq %%fs:0x0, %0" : "=r"(tls));
#else
#error Port.
#endif // ARCH_CPU_ARMEL
return tls;
}
TEST(ProcessReader, SelfBasic) {
ProcessReader process_reader;
ASSERT_TRUE(process_reader.Initialize(getpid()));
#if !defined(ARCH_CPU_64_BITS)
EXPECT_FALSE(process_reader.Is64Bit());
#else
EXPECT_TRUE(process_reader.Is64Bit());
#endif
EXPECT_EQ(process_reader.ProcessID(), getpid());
EXPECT_EQ(process_reader.ParentProcessID(), getppid());
static constexpr char kTestMemory[] = "Some test memory";
char buffer[arraysize(kTestMemory)];
ASSERT_TRUE(process_reader.Memory()->Read(
reinterpret_cast<LinuxVMAddress>(kTestMemory),
sizeof(kTestMemory),
&buffer));
EXPECT_STREQ(kTestMemory, buffer);
}
constexpr char kTestMemory[] = "Read me from another process";
class BasicChildTest : public Multiprocess {
public:
BasicChildTest() : Multiprocess() {}
~BasicChildTest() {}
private:
void MultiprocessParent() override {
ProcessReader process_reader;
ASSERT_TRUE(process_reader.Initialize(ChildPID()));
#if !defined(ARCH_CPU_64_BITS)
EXPECT_FALSE(process_reader.Is64Bit());
#else
EXPECT_TRUE(process_reader.Is64Bit());
#endif
EXPECT_EQ(process_reader.ParentProcessID(), getpid());
EXPECT_EQ(process_reader.ProcessID(), ChildPID());
std::string read_string;
ASSERT_TRUE(process_reader.Memory()->ReadCString(
reinterpret_cast<LinuxVMAddress>(kTestMemory), &read_string));
EXPECT_EQ(read_string, kTestMemory);
}
void MultiprocessChild() override { CheckedReadFileAtEOF(ReadPipeHandle()); }
DISALLOW_COPY_AND_ASSIGN(BasicChildTest);
};
TEST(ProcessReader, ChildBasic) {
BasicChildTest test;
test.Run();
}
class TestThreadPool {
public:
struct ThreadExpectation {
LinuxVMAddress tls = 0;
LinuxVMAddress stack_address = 0;
LinuxVMSize max_stack_size = 0;
int sched_policy = 0;
int static_priority = 0;
int nice_value = 0;
};
TestThreadPool() : threads_() {}
~TestThreadPool() {
for (Thread* thread : threads_) {
thread->exit_semaphore.Signal();
}
for (const Thread* thread : threads_) {
EXPECT_EQ(pthread_join(thread->pthread, nullptr), 0)
<< ErrnoMessage("pthread_join");
}
}
void StartThreads(size_t thread_count, size_t stack_size = 0) {
for (size_t thread_index = 0; thread_index < thread_count; ++thread_index) {
Thread* thread = new Thread();
threads_.push_back(thread);
pthread_attr_t attr;
ASSERT_EQ(pthread_attr_init(&attr), 0)
<< ErrnoMessage("pthread_attr_init");
if (stack_size > 0) {
void* stack_ptr;
errno = posix_memalign(&stack_ptr, getpagesize(), stack_size);
ASSERT_EQ(errno, 0) << ErrnoMessage("posix_memalign");
thread->stack.reset(reinterpret_cast<char*>(stack_ptr));
ASSERT_EQ(pthread_attr_setstack(&attr, thread->stack.get(), stack_size),
0)
<< ErrnoMessage("pthread_attr_setstack");
thread->expectation.max_stack_size = stack_size;
}
ASSERT_EQ(pthread_attr_setschedpolicy(&attr, SCHED_OTHER), 0)
<< ErrnoMessage("pthread_attr_setschedpolicy");
thread->expectation.sched_policy = SCHED_OTHER;
sched_param param;
param.sched_priority = 0;
ASSERT_EQ(pthread_attr_setschedparam(&attr, &param), 0)
<< ErrnoMessage("pthread_attr_setschedparam");
thread->expectation.static_priority = 0;
thread->expectation.nice_value = thread_index % 20;
ASSERT_EQ(pthread_create(&thread->pthread, &attr, ThreadMain, thread), 0)
<< ErrnoMessage("pthread_create");
}
for (Thread* thread : threads_) {
thread->ready_semaphore.Wait();
}
}
pid_t GetThreadExpectation(size_t thread_index,
ThreadExpectation* expectation) {
CHECK_LT(thread_index, threads_.size());
const Thread* thread = threads_[thread_index];
*expectation = thread->expectation;
return thread->tid;
}
private:
struct Thread {
Thread()
: pthread(),
expectation(),
ready_semaphore(0),
exit_semaphore(0),
tid(-1) {}
~Thread() {}
pthread_t pthread;
ThreadExpectation expectation;
std::unique_ptr<char[], base::FreeDeleter> stack;
Semaphore ready_semaphore;
Semaphore exit_semaphore;
pid_t tid;
};
static void* ThreadMain(void* argument) {
Thread* thread = static_cast<Thread*>(argument);
CHECK_EQ(setpriority(PRIO_PROCESS, 0, thread->expectation.nice_value), 0)
<< ErrnoMessage("setpriority");
thread->expectation.tls = GetTLS();
thread->expectation.stack_address =
reinterpret_cast<LinuxVMAddress>(&thread);
thread->tid = gettid();
thread->ready_semaphore.Signal();
thread->exit_semaphore.Wait();
CHECK_EQ(pthread_self(), thread->pthread);
return nullptr;
}
PointerVector<Thread> threads_;
DISALLOW_COPY_AND_ASSIGN(TestThreadPool);
};
using ThreadMap = std::map<pid_t, TestThreadPool::ThreadExpectation>;
void ExpectThreads(const ThreadMap& thread_map,
const std::vector<ProcessReader::Thread>& threads,
const pid_t pid) {
ASSERT_EQ(threads.size(), thread_map.size());
MemoryMap memory_map;
ASSERT_TRUE(memory_map.Initialize(pid));
for (const auto& thread : threads) {
SCOPED_TRACE(base::StringPrintf("Thread id %d, tls 0x%" PRIx64
", stack addr 0x%" PRIx64
", stack size 0x%" PRIx64,
thread.tid,
thread.thread_specific_data_address,
thread.stack_region_address,
thread.stack_region_size));
const auto& iterator = thread_map.find(thread.tid);
ASSERT_NE(iterator, thread_map.end());
EXPECT_EQ(thread.thread_specific_data_address, iterator->second.tls);
ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address));
EXPECT_LE(thread.stack_region_address, iterator->second.stack_address);
ASSERT_TRUE(memory_map.FindMapping(thread.stack_region_address +
thread.stack_region_size - 1));
EXPECT_GE(thread.stack_region_address + thread.stack_region_size,
iterator->second.stack_address);
if (iterator->second.max_stack_size) {
EXPECT_LT(thread.stack_region_size, iterator->second.max_stack_size);
}
EXPECT_EQ(thread.sched_policy, iterator->second.sched_policy);
EXPECT_EQ(thread.static_priority, iterator->second.static_priority);
EXPECT_EQ(thread.nice_value, iterator->second.nice_value);
}
}
class ChildThreadTest : public Multiprocess {
public:
ChildThreadTest(size_t stack_size = 0)
: Multiprocess(), stack_size_(stack_size) {}
~ChildThreadTest() {}
private:
void MultiprocessParent() override {
ThreadMap thread_map;
for (size_t thread_index = 0; thread_index < kThreadCount + 1;
++thread_index) {
pid_t tid;
TestThreadPool::ThreadExpectation expectation;
CheckedReadFileExactly(ReadPipeHandle(), &tid, sizeof(tid));
CheckedReadFileExactly(
ReadPipeHandle(), &expectation, sizeof(expectation));
thread_map[tid] = expectation;
}
ProcessReader process_reader;
ASSERT_TRUE(process_reader.Initialize(ChildPID()));
const std::vector<ProcessReader::Thread>& threads =
process_reader.Threads();
ExpectThreads(thread_map, threads, ChildPID());
}
void MultiprocessChild() override {
TestThreadPool thread_pool;
thread_pool.StartThreads(kThreadCount, stack_size_);
TestThreadPool::ThreadExpectation expectation;
expectation.tls = GetTLS();
expectation.stack_address = reinterpret_cast<LinuxVMAddress>(&thread_pool);
int res = sched_getscheduler(0);
ASSERT_GE(res, 0) << ErrnoMessage("sched_getscheduler");
expectation.sched_policy = res;
sched_param param;
ASSERT_EQ(sched_getparam(0, &param), 0) << ErrnoMessage("sched_getparam");
expectation.static_priority = param.sched_priority;
errno = 0;
res = getpriority(PRIO_PROCESS, 0);
ASSERT_FALSE(res == -1 && errno) << ErrnoMessage("getpriority");
expectation.nice_value = res;
pid_t tid = gettid();
CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid));
CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation));
for (size_t thread_index = 0; thread_index < kThreadCount; ++thread_index) {
tid = thread_pool.GetThreadExpectation(thread_index, &expectation);
CheckedWriteFile(WritePipeHandle(), &tid, sizeof(tid));
CheckedWriteFile(WritePipeHandle(), &expectation, sizeof(expectation));
}
CheckedReadFileAtEOF(ReadPipeHandle());
}
static constexpr size_t kThreadCount = 3;
const size_t stack_size_;
DISALLOW_COPY_AND_ASSIGN(ChildThreadTest);
};
TEST(ProcessReader, ChildWithThreads) {
ChildThreadTest test;
test.Run();
}
TEST(ProcessReader, ChildThreadsWithSmallUserStacks) {
ChildThreadTest test(PTHREAD_STACK_MIN);
test.Run();
}
// Tests a thread with a stack that spans multiple mappings.
class ChildWithSplitStackTest : public Multiprocess {
public:
ChildWithSplitStackTest() : Multiprocess(), page_size_(getpagesize()) {}
~ChildWithSplitStackTest() {}
private:
void MultiprocessParent() override {
LinuxVMAddress stack_addr1;
LinuxVMAddress stack_addr2;
LinuxVMAddress stack_addr3;
CheckedReadFileExactly(ReadPipeHandle(), &stack_addr1, sizeof(stack_addr1));
CheckedReadFileExactly(ReadPipeHandle(), &stack_addr2, sizeof(stack_addr2));
CheckedReadFileExactly(ReadPipeHandle(), &stack_addr3, sizeof(stack_addr3));
ProcessReader process_reader;
ASSERT_TRUE(process_reader.Initialize(ChildPID()));
const std::vector<ProcessReader::Thread>& threads =
process_reader.Threads();
ASSERT_EQ(threads.size(), 1u);
LinuxVMAddress thread_stack_start = threads[0].stack_region_address;
EXPECT_LE(thread_stack_start, stack_addr1);
EXPECT_LE(thread_stack_start, stack_addr2);
EXPECT_LE(thread_stack_start, stack_addr3);
LinuxVMAddress thread_stack_end =
thread_stack_start + threads[0].stack_region_size;
EXPECT_GE(thread_stack_end, stack_addr1);
EXPECT_GE(thread_stack_end, stack_addr2);
EXPECT_GE(thread_stack_end, stack_addr3);
}
void MultiprocessChild() override {
const LinuxVMSize stack_size = page_size_ * 3;
GrowStack(stack_size, reinterpret_cast<LinuxVMAddress>(&stack_size));
}
void GrowStack(LinuxVMSize stack_size, LinuxVMAddress bottom_of_stack) {
char stack_contents[4096];
auto stack_address = reinterpret_cast<LinuxVMAddress>(&stack_contents);
if (bottom_of_stack - stack_address < stack_size) {
GrowStack(stack_size, bottom_of_stack);
} else {
// Write-protect a page on our stack to split up the mapping
LinuxVMAddress page_addr =
stack_address - (stack_address % page_size_) + page_size_;
ASSERT_EQ(
mprotect(reinterpret_cast<void*>(page_addr), page_size_, PROT_READ),
0)
<< ErrnoMessage("mprotect");
CheckedWriteFile(
WritePipeHandle(), &bottom_of_stack, sizeof(bottom_of_stack));
CheckedWriteFile(WritePipeHandle(), &page_addr, sizeof(page_addr));
CheckedWriteFile(
WritePipeHandle(), &stack_address, sizeof(stack_address));
// Wait for parent to read us
CheckedReadFileAtEOF(ReadPipeHandle());
ASSERT_EQ(mprotect(reinterpret_cast<void*>(page_addr),
page_size_,
PROT_READ | PROT_WRITE),
0)
<< ErrnoMessage("mprotect");
}
}
const size_t page_size_;
DISALLOW_COPY_AND_ASSIGN(ChildWithSplitStackTest);
};
TEST(ProcessReader, ChildWithSplitStack) {
ChildWithSplitStackTest test;
test.Run();
}
} // namespace
} // namespace test
} // namespace crashpad

View File

@ -0,0 +1,18 @@
# Copyright 2017 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.
# This symbol is used by elf_image_reader_test.cc.
{
ElfImageReaderTestExportedSymbol;
};

View File

@ -0,0 +1,204 @@
// Copyright 2017 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 "snapshot/linux/thread_snapshot_linux.h"
#include <sched.h>
#include "base/logging.h"
#include "snapshot/linux/cpu_context_linux.h"
#include "util/misc/reinterpret_bytes.h"
namespace crashpad {
namespace internal {
ThreadSnapshotLinux::ThreadSnapshotLinux()
: ThreadSnapshot(),
context_union_(),
context_(),
stack_(),
thread_specific_data_address_(0),
thread_id_(-1),
priority_(-1),
initialized_() {
}
ThreadSnapshotLinux::~ThreadSnapshotLinux() {
}
bool ThreadSnapshotLinux::Initialize(
ProcessReader* process_reader,
const ProcessReader::Thread& thread) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
if (process_reader->Is64Bit()) {
context_.architecture = kCPUArchitectureX86_64;
context_.x86_64 = &context_union_.x86_64;
InitializeCPUContextX86_64(thread.thread_context.t64,
thread.float_context.f64,
context_.x86_64);
} else {
context_.architecture = kCPUArchitectureX86;
context_.x86 = &context_union_.x86;
InitializeCPUContextX86(thread.thread_context.t32,
thread.float_context.f32,
context_.x86);
}
#else
#error Port.
#endif
stack_.Initialize(process_reader,
thread.stack_region_address,
thread.stack_region_size);
thread_specific_data_address_ =
thread.thread_specific_data_address;
thread_id_ = thread.tid;
// Map Linux scheduling policy, static priority, and nice value into a single
// int value.
//
// The possible policies in order of approximate priority (low to high) are
// SCHED_IDLE
// SCHED_BATCH
// SCHED_OTHER
// SCHED_RR
// SCHED_FIFO
//
// static_priority is not used for OTHER, BATCH, or IDLE and should be 0.
// For FIFO and RR, static_priority should range from 1 to 99 with 99 being
// the highest priority.
//
// nice value ranges from -20 to 19, with -20 being highest priority
enum class Policy : uint8_t {
kUnknown = 0,
kIdle,
kBatch,
kOther,
kRR,
kFIFO
};
struct LinuxPriority {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
// nice values affect how dynamic priorities are updated, which only matters
// for threads with the same static priority.
uint8_t nice_value = 0;
// The scheduling policy also affects how threads with the same static
// priority are ordered, but has greater impact than nice value.
Policy policy = Policy::kUnknown;
// The static priority is the most significant in determining overall
// priority.
uint8_t static_priority = 0;
// Put this in the most significant byte position to prevent negative
// priorities.
uint8_t unused = 0;
#elif defined(ARCH_CPU_BIG_ENDIAN)
uint8_t unused = 0;
uint8_t static_priority = 0;
Policy policy = Policy::kUnknown;
uint8_t nice_value = 0;
#endif // ARCH_CPU_LITTLE_ENDIAN
};
static_assert(sizeof(LinuxPriority) <= sizeof(int), "priority is too large");
LinuxPriority prio;
// Lower nice values have higher priority, so negate them and add 20 to put
// them in the range 1-40 with 40 being highest priority.
if (thread.nice_value < -20 || thread.nice_value > 19) {
LOG(WARNING) << "invalid nice value " << thread.nice_value;
prio.nice_value = 0;
} else {
prio.nice_value = -1 * thread.nice_value + 20;
}
switch (thread.sched_policy) {
case SCHED_IDLE:
prio.policy = Policy::kIdle;
break;
case SCHED_BATCH:
prio.policy = Policy::kBatch;
break;
case SCHED_OTHER:
prio.policy = Policy::kOther;
break;
case SCHED_RR:
prio.policy = Policy::kRR;
break;
case SCHED_FIFO:
prio.policy = Policy::kFIFO;
break;
default:
prio.policy = Policy::kUnknown;
LOG(WARNING) << "Unknown scheduling policy " << thread.sched_policy;
}
if (thread.static_priority < 0 || thread.static_priority > 99) {
LOG(WARNING) << "invalid static priority " << thread.static_priority;
}
prio.static_priority = thread.static_priority;
if (!ReinterpretBytes(prio, &priority_)) {
LOG(ERROR) << "Couldn't set priority";
return false;
}
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
const CPUContext* ThreadSnapshotLinux::Context() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &context_;
}
const MemorySnapshot* ThreadSnapshotLinux::Stack() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return &stack_;
}
uint64_t ThreadSnapshotLinux::ThreadID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return thread_id_;
}
int ThreadSnapshotLinux::SuspendCount() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return 0;
}
int ThreadSnapshotLinux::Priority() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return priority_;
}
uint64_t ThreadSnapshotLinux::ThreadSpecificDataAddress() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return thread_specific_data_address_;
}
std::vector<const MemorySnapshot*> ThreadSnapshotLinux::ExtraMemory() const {
return std::vector<const MemorySnapshot*>();
}
} // namespace internal
} // namespace crashpad

View File

@ -0,0 +1,82 @@
// Copyright 2017 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.
#ifndef CRASHPAD_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_
#define CRASHPAD_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_
#include <stdint.h>
#include "base/macros.h"
#include "build/build_config.h"
#include "snapshot/cpu_context.h"
#include "snapshot/linux/memory_snapshot_linux.h"
#include "snapshot/linux/process_reader.h"
#include "snapshot/memory_snapshot.h"
#include "snapshot/thread_snapshot.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
namespace internal {
//! \brief A ThreadSnapshot of a thread on a Linux system.
class ThreadSnapshotLinux final : public ThreadSnapshot {
public:
ThreadSnapshotLinux();
~ThreadSnapshotLinux() override;
//! \brief Initializes the object.
//!
//! \param[in] process_reader A ProcessReader for the process containing the
//! thread.
//! \param[in] thread The thread within the ProcessReader for
//! which the snapshot should be created.
//!
//! \return `true` if the snapshot could be created, `false` otherwise with
//! a message logged.
bool Initialize(ProcessReader* process_reader,
const ProcessReader::Thread& thread);
// ThreadSnapshot:
const CPUContext* Context() const override;
const MemorySnapshot* Stack() const override;
uint64_t ThreadID() const override;
int SuspendCount() const override;
int Priority() const override;
uint64_t ThreadSpecificDataAddress() const override;
std::vector<const MemorySnapshot*> ExtraMemory() const override;
private:
#if defined(ARCH_CPU_X86_FAMILY)
union {
CPUContextX86 x86;
CPUContextX86_64 x86_64;
} context_union_;
#else
#error Port.
#endif // ARCH_CPU_X86_FAMILY
CPUContext context_;
MemorySnapshotLinux stack_;
LinuxVMAddress thread_specific_data_address_;
pid_t thread_id_;
int priority_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ThreadSnapshotLinux);
};
} // namespace internal
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_LINUX_THREAD_SNAPSHOT_LINUX_H_

View File

@ -91,7 +91,7 @@ void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations(
// This number was totally made up out of nowhere, but it seems prudent to
// enforce some limit.
const size_t kMaxMessageSize = 1024;
constexpr size_t kMaxMessageSize = 1024;
if (crash_info.message) {
std::string message;
if (process_reader_->Memory()->ReadCStringSizeLimited(

View File

@ -212,7 +212,8 @@ class TestMachOImageAnnotationsReader final
// dyld exposes its error_string at least as far back as Mac OS X 10.4.
if (test_type_ == kCrashDyld) {
const char kExpectedAnnotation[] = "could not load inserted library";
static constexpr char kExpectedAnnotation[] =
"could not load inserted library";
size_t expected_annotation_length = strlen(kExpectedAnnotation);
bool found = false;
for (const std::string& annotation : all_annotations_vector) {

View File

@ -33,7 +33,7 @@
namespace {
const uint32_t kInvalidSegmentIndex = std::numeric_limits<uint32_t>::max();
constexpr uint32_t kInvalidSegmentIndex = std::numeric_limits<uint32_t>::max();
} // namespace

View File

@ -47,16 +47,16 @@ namespace {
// are different.
#if defined(ARCH_CPU_64_BITS)
using MachHeader = mach_header_64;
const uint32_t kMachMagic = MH_MAGIC_64;
constexpr uint32_t kMachMagic = MH_MAGIC_64;
using SegmentCommand = segment_command_64;
const uint32_t kSegmentCommand = LC_SEGMENT_64;
constexpr uint32_t kSegmentCommand = LC_SEGMENT_64;
using Section = section_64;
using Nlist = nlist_64;
#else
using MachHeader = mach_header;
const uint32_t kMachMagic = MH_MAGIC;
constexpr uint32_t kMachMagic = MH_MAGIC;
using SegmentCommand = segment_command;
const uint32_t kSegmentCommand = LC_SEGMENT;
constexpr uint32_t kSegmentCommand = LC_SEGMENT;
using Section = section;
// This needs to be called “struct nlist” because “nlist” without the struct
@ -65,9 +65,9 @@ using Nlist = struct nlist;
#endif
#if defined(ARCH_CPU_X86_64)
const int kCPUType = CPU_TYPE_X86_64;
constexpr int kCPUType = CPU_TYPE_X86_64;
#elif defined(ARCH_CPU_X86)
const int kCPUType = CPU_TYPE_X86;
constexpr int kCPUType = CPU_TYPE_X86;
#endif
// Verifies that |expect_section| and |actual_section| agree.
@ -327,7 +327,8 @@ void ExpectSegmentCommands(const MachHeader* expect_image,
// In some cases, the expected slide value for an image is unknown, because no
// reasonable API to return it is provided. When this happens, use kSlideUnknown
// to avoid checking the actual slide value against anything.
const mach_vm_size_t kSlideUnknown = std::numeric_limits<mach_vm_size_t>::max();
constexpr mach_vm_size_t kSlideUnknown =
std::numeric_limits<mach_vm_size_t>::max();
// Verifies that |expect_image| is a vaild Mach-O header for the current system
// by checking its |magic| and |cputype| fields. Then, verifies that the

View File

@ -53,7 +53,7 @@ TEST(MachOImageSegmentReader, SegmentNameString) {
// Segment names defined in <mach-o/loader.h>. All of these should come
// through SegmentNameString() cleanly and without truncation.
const char* kSegmentTestData[] = {
static constexpr const char* kSegmentTestData[] = {
SEG_TEXT,
SEG_DATA,
SEG_OBJC,
@ -91,7 +91,7 @@ TEST(MachOImageSegmentReader, SectionNameString) {
// Section names defined in <mach-o/loader.h>. All of these should come
// through SectionNameString() cleanly and without truncation.
const char* kSectionTestData[] = {
static constexpr const char* kSectionTestData[] = {
SECT_TEXT,
SECT_FVMLIB_INIT0,
SECT_FVMLIB_INIT1,
@ -115,12 +115,11 @@ TEST(MachOImageSegmentReader, SectionNameString) {
}
TEST(MachOImageSegmentReader, SegmentAndSectionNameString) {
struct SegmentAndSectionTestData {
static constexpr struct {
const char* segment;
const char* section;
const char* output;
};
const SegmentAndSectionTestData kSegmentAndSectionTestData[] = {
} kSegmentAndSectionTestData[] = {
{"segment", "section", "segment,section"},
{"Segment", "Section", "Segment,Section"},
{"SEGMENT", "SECTION", "SEGMENT,SECTION"},
@ -172,7 +171,7 @@ TEST(MachOImageSegmentReader, SegmentAndSectionNameString) {
for (size_t index = 0; index < arraysize(kSegmentAndSectionTestData);
++index) {
const SegmentAndSectionTestData& test = kSegmentAndSectionTestData[index];
const auto& test = kSegmentAndSectionTestData[index];
EXPECT_EQ(MachOImageSegmentReader::SegmentAndSectionNameString(
test.segment, test.section),
test.output)

View File

@ -611,7 +611,7 @@ mach_vm_address_t ProcessReader::CalculateStackRegion(
// Regardless of whether the ABI requires a red zone, capture up to
// kExtraCaptureSize additional bytes of stack, but only if present in the
// region that was already found.
const mach_vm_size_t kExtraCaptureSize = 128;
constexpr mach_vm_size_t kExtraCaptureSize = 128;
start_address = std::max(start_address >= kExtraCaptureSize
? start_address - kExtraCaptureSize
: start_address,
@ -620,7 +620,7 @@ mach_vm_address_t ProcessReader::CalculateStackRegion(
// Align start_address to a 16-byte boundary, which can help readers by
// ensuring that data is aligned properly. This could page-align instead,
// but that might be wasteful.
const mach_vm_size_t kDesiredAlignment = 16;
constexpr mach_vm_size_t kDesiredAlignment = 16;
start_address &= ~(kDesiredAlignment - 1);
DCHECK_GE(start_address, region_base);
}
@ -685,7 +685,7 @@ void ProcessReader::LocateRedZone(mach_vm_address_t* const start_address,
// x86_64 has a red zone. See AMD64 ABI 0.99.6,
// http://www.x86-64.org/documentation/abi.pdf, section 3.2.2, “The Stack
// Frame”.
const mach_vm_size_t kRedZoneSize = 128;
constexpr mach_vm_size_t kRedZoneSize = 128;
mach_vm_address_t red_zone_base =
*start_address >= kRedZoneSize ? *start_address - kRedZoneSize : 0;
bool red_zone_ok = false;

View File

@ -58,7 +58,7 @@ namespace crashpad {
namespace test {
namespace {
const char kDyldPath[] = "/usr/lib/dyld";
constexpr char kDyldPath[] = "/usr/lib/dyld";
TEST(ProcessReader, SelfBasic) {
ProcessReader process_reader;
@ -73,7 +73,7 @@ TEST(ProcessReader, SelfBasic) {
EXPECT_EQ(process_reader.ProcessID(), getpid());
EXPECT_EQ(process_reader.ParentProcessID(), getppid());
const char kTestMemory[] = "Some test memory";
static constexpr char kTestMemory[] = "Some test memory";
char buffer[arraysize(kTestMemory)];
ASSERT_TRUE(process_reader.Memory()->Read(
FromPointerCast<mach_vm_address_t>(kTestMemory),
@ -82,7 +82,7 @@ TEST(ProcessReader, SelfBasic) {
EXPECT_STREQ(kTestMemory, buffer);
}
const char kTestMemory[] = "Read me from another process";
constexpr char kTestMemory[] = "Read me from another process";
class ProcessReaderChild final : public MachMultiprocess {
public:
@ -384,7 +384,7 @@ TEST(ProcessReader, SelfSeveralThreads) {
ASSERT_TRUE(process_reader.Initialize(mach_task_self()));
TestThreadPool thread_pool;
const size_t kChildThreads = 16;
constexpr size_t kChildThreads = 16;
ASSERT_NO_FATAL_FAILURE(thread_pool.StartThreads(kChildThreads));
// Build a map of all expected threads, keyed by each threads ID. The values
@ -523,13 +523,13 @@ class ProcessReaderThreadedChild final : public MachMultiprocess {
TEST(ProcessReader, ChildOneThread) {
// The main thread plus zero child threads equals one thread.
const size_t kChildThreads = 0;
constexpr size_t kChildThreads = 0;
ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads);
process_reader_threaded_child.Run();
}
TEST(ProcessReader, ChildSeveralThreads) {
const size_t kChildThreads = 64;
constexpr size_t kChildThreads = 64;
ProcessReaderThreadedChild process_reader_threaded_child(kChildThreads);
process_reader_threaded_child.Run();
}

View File

@ -65,7 +65,7 @@ bool ReadIntoVersioned(ProcessReader* process_reader,
template <typename Traits>
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(
decltype(dyld_all_image_infos<Traits>::version) version) {
const size_t kSizeForVersion[] = {
static constexpr size_t kSizeForVersion[] = {
offsetof(dyld_all_image_infos<Traits>, infoArrayCount), // 0
offsetof(dyld_all_image_infos<Traits>, libSystemInitialized), // 1
offsetof(dyld_all_image_infos<Traits>, jitInfo), // 2

View File

@ -364,9 +364,9 @@ void SystemSnapshotMac::TimeZone(DaylightSavingTimeStatus* dst_status,
// no transitions to or from daylight saving time occurred or will occur
// within a year of the current date. Arizona, which last observed daylight
// saving time in 1967, is an example.
const int kMonthDeltas[] =
{ 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12 };
static constexpr int kMonthDeltas[] =
{0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6,
7, -7, 8, -8, 9, -9, 10, -10, 11, -11, 12, -12};
for (size_t index = 0;
index < arraysize(kMonthDeltas) && !found_transition;
++index) {

View File

@ -210,7 +210,7 @@ TEST_F(SystemSnapshotMacTest, TimeZone) {
// standard_name and daylight_name can be nullptr where no name exists to
// verify, as may happen when some versions of the timezone database carry
// invented names and others do not.
const struct {
static constexpr struct {
const char* tz;
bool observes_dst;
float standard_offset_hours;

View File

@ -40,6 +40,22 @@
'exception_snapshot.h',
'handle_snapshot.cc',
'handle_snapshot.h',
'linux/cpu_context_linux.cc',
'linux/cpu_context_linux.h',
'linux/debug_rendezvous.cc',
'linux/debug_rendezvous.h',
'linux/elf_dynamic_array_reader.cc',
'linux/elf_dynamic_array_reader.h',
'linux/elf_image_reader.cc',
'linux/elf_image_reader.h',
'linux/elf_symbol_table_reader.cc',
'linux/elf_symbol_table_reader.h',
'linux/memory_snapshot_linux.cc',
'linux/memory_snapshot_linux.h',
'linux/process_reader.cc',
'linux/process_reader.h',
'linux/thread_snapshot_linux.cc',
'linux/thread_snapshot_linux.h',
'mac/cpu_context_mac.cc',
'mac/cpu_context_mac.h',
'mac/exception_snapshot_mac.cc',
@ -130,7 +146,20 @@
],
},
}],
]
['OS=="linux" or OS=="android"', {
'sources!': [
'capture_memory.cc',
'capture_memory.h',
],
}],
],
'target_conditions': [
['OS=="android"', {
'sources/': [
['include', '^linux/'],
],
}],
],
},
{
'variables': {

View File

@ -70,6 +70,9 @@
'cpu_context_test.cc',
'crashpad_info_client_options_test.cc',
'api/module_annotations_win_test.cc',
'linux/debug_rendezvous_test.cc',
'linux/elf_image_reader_test.cc',
'linux/process_reader_test.cc',
'mac/cpu_context_mac_test.cc',
'mac/mach_o_image_annotations_reader_test.cc',
'mac/mach_o_image_reader_test.cc',
@ -107,6 +110,32 @@
'crashpad_snapshot_test_image_reader_module',
],
}],
['OS=="linux" or OS=="android"', {
'sources!': [
'crashpad_info_client_options_test.cc',
],
'copies': [{
'destination': '<(PRODUCT_DIR)',
'files': [
'linux/test_exported_symbols.sym',
],
}],
'ldflags': [
'-Wl,--dynamic-list=test_exported_symbols.sym',
],
'link_settings': {
'libraries': [
'-ldl',
],
},
}],
],
'target_conditions': [
['OS=="android"', {
'sources/': [
['include', '^linux/'],
],
}],
],
},
{

View File

@ -102,7 +102,7 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate {
// Verify the exception happened at the expected location with a bit of
// slop space to allow for reading the current PC before the exception
// happens. See TestCrashingChild().
const uint64_t kAllowedOffset = 64;
constexpr uint64_t kAllowedOffset = 64;
EXPECT_GT(snapshot.Exception()->ExceptionAddress(), break_near_);
EXPECT_LT(snapshot.Exception()->ExceptionAddress(),
break_near_ + kAllowedOffset);
@ -205,7 +205,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate {
// Verify the dump was captured at the expected location with some slop
// space.
const uint64_t kAllowedOffset = 64;
constexpr uint64_t kAllowedOffset = 64;
EXPECT_GT(snapshot.Exception()->Context()->InstructionPointer(),
dump_near_);
EXPECT_LT(snapshot.Exception()->Context()->InstructionPointer(),

View File

@ -128,7 +128,7 @@ TEST(PEImageReader, VSFixedFileInfo_OneModule) {
ASSERT_TRUE(process_reader.Initialize(GetCurrentProcess(),
ProcessSuspensionState::kRunning));
const wchar_t kModuleName[] = L"kernel32.dll";
static constexpr wchar_t kModuleName[] = L"kernel32.dll";
const HMODULE module_handle = GetModuleHandle(kModuleName);
ASSERT_TRUE(module_handle) << ErrorMessage("GetModuleHandle");

View File

@ -41,14 +41,14 @@ TEST(ProcessReaderWin, SelfBasic) {
EXPECT_EQ(process_reader.GetProcessInfo().ProcessID(), GetCurrentProcessId());
const char kTestMemory[] = "Some test memory";
static constexpr char kTestMemory[] = "Some test memory";
char buffer[arraysize(kTestMemory)];
ASSERT_TRUE(process_reader.ReadMemory(
reinterpret_cast<uintptr_t>(kTestMemory), sizeof(kTestMemory), &buffer));
EXPECT_STREQ(kTestMemory, buffer);
}
const char kTestMemory[] = "Read me from another process";
constexpr char kTestMemory[] = "Read me from another process";
class ProcessReaderChild final : public WinMultiprocess {
public:

View File

@ -528,7 +528,7 @@ WinVMSize ProcessSnapshotWin::DetermineSizeOfEnvironmentBlock(
&env_block[0]);
env_block.resize(
static_cast<unsigned int>(bytes_read / sizeof(env_block[0])));
const wchar_t terminator[] = { 0, 0 };
static constexpr wchar_t terminator[] = {0, 0};
size_t at = env_block.find(std::wstring(terminator, arraysize(terminator)));
if (at != std::wstring::npos)
env_block.resize(at + arraysize(terminator));
@ -554,7 +554,7 @@ void ProcessSnapshotWin::ReadLock(
AddMemorySnapshot(
start, sizeof(process_types::RTL_CRITICAL_SECTION<Traits>), into);
const decltype(critical_section.DebugInfo) kInvalid =
constexpr decltype(critical_section.DebugInfo) kInvalid =
static_cast<decltype(critical_section.DebugInfo)>(-1);
if (critical_section.DebugInfo == kInvalid)
return;

View File

@ -98,7 +98,7 @@ void SystemSnapshotWin::Initialize(ProcessReaderWin* process_reader) {
os_server_ = version_info.wProductType != VER_NT_WORKSTATION;
}
const wchar_t kSystemDll[] = L"kernel32.dll";
static constexpr wchar_t kSystemDll[] = L"kernel32.dll";
VS_FIXEDFILEINFO ffi;
if (GetModuleVersionAndType(base::FilePath(kSystemDll), &ffi)) {
std::string flags_string = GetStringForFileFlags(ffi.dwFileFlags);
@ -192,7 +192,7 @@ void SystemSnapshotWin::CPUFrequency(uint64_t* current_hz,
*max_hz = 0;
return;
}
const uint64_t kMhzToHz = static_cast<uint64_t>(1E6);
constexpr uint64_t kMhzToHz = static_cast<uint64_t>(1E6);
*current_hz = std::max_element(info.begin(),
info.end(),
[](const PROCESSOR_POWER_INFORMATION& a,

View File

@ -28,11 +28,11 @@ bool FileExists(const base::FilePath& path) {
#if defined(OS_POSIX)
struct stat st;
int rv = lstat(path.value().c_str(), &st);
const char stat_function[] = "lstat";
static constexpr char stat_function[] = "lstat";
#elif defined(OS_WIN)
struct _stat st;
int rv = _wstat(path.value().c_str(), &st);
const char stat_function[] = "_wstat";
static constexpr char stat_function[] = "_wstat";
#else
#error "Not implemented"
#endif
@ -48,11 +48,11 @@ FileOffset FileSize(const base::FilePath& path) {
#if defined(OS_POSIX)
struct stat st;
int rv = lstat(path.value().c_str(), &st);
const char stat_function[] = "lstat";
static constexpr char stat_function[] = "lstat";
#elif defined(OS_WIN)
struct _stati64 st;
int rv = _wstati64(path.value().c_str(), &st);
const char stat_function[] = "_wstati64";
static constexpr char stat_function[] = "_wstati64";
#else
#error "Not implemented"
#endif

View File

@ -24,7 +24,7 @@ namespace {
TEST(HexString, HexString) {
EXPECT_EQ(BytesToHexString(nullptr, 0), "");
const char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_";
static constexpr char kBytes[] = "Abc123xyz \x0a\x7f\xf0\x9f\x92\xa9_";
EXPECT_EQ(BytesToHexString(kBytes, arraysize(kBytes)),
"41626331323378797a200a7ff09f92a95f00");
}

View File

@ -38,7 +38,7 @@ base::FilePath GenerateCandidateName() {
return system_temp_dir.Append(new_dir_name);
}
const int kRetries = 50;
constexpr int kRetries = 50;
} // namespace

View File

@ -35,7 +35,7 @@ namespace test {
namespace {
const char kIsMultiprocessChild[] = "--is-multiprocess-child";
constexpr char kIsMultiprocessChild[] = "--is-multiprocess-child";
bool GetSwitch(const char* switch_name, std::string* value) {
int num_args;

View File

@ -103,10 +103,20 @@
'zlib_crashpad.h',
],
'conditions': [
['target_arch=="x86" or target_arch=="amd64"', {
['target_arch=="ia32" or target_arch=="x64"', {
'sources!': [
'zlib/simd_stub.c',
],
'cflags': [
'-msse4.2',
'-mpclmul',
],
'xcode_settings': {
'OTHER_CFLAGS': [
'-msse4.2',
'-mpclmul',
],
},
}, {
'sources!': [
'zlib/crc_folding.c',

View File

@ -92,7 +92,7 @@ struct Options {
// performed. Various string representations of a boolean are recognized
// case-insensitively.
bool StringToBool(const char* string, bool* boolean) {
const char* const kFalseWords[] = {
static constexpr const char* kFalseWords[] = {
"0",
"false",
"no",
@ -100,7 +100,7 @@ bool StringToBool(const char* string, bool* boolean) {
"disabled",
"clear",
};
const char* const kTrueWords[] = {
static constexpr const char* kTrueWords[] = {
"1",
"true",
"yes",
@ -153,7 +153,7 @@ bool StringToTime(const char* string, time_t* out_time, bool utc) {
const char* end = string + strlen(string);
const char* const kFormats[] = {
static constexpr const char* kFormats[] = {
"%Y-%m-%d %H:%M:%S %Z",
"%Y-%m-%d %H:%M:%S",
"%+",
@ -294,7 +294,7 @@ int DatabaseUtilMain(int argc, char* argv[]) {
kOptionVersion = -3,
};
const option long_options[] = {
static constexpr option long_options[] = {
{"create", no_argument, nullptr, kOptionCreate},
{"database", required_argument, nullptr, kOptionDatabase},
{"show-client-id", no_argument, nullptr, kOptionShowClientID},

View File

@ -74,7 +74,7 @@ int HTTPUploadMain(int argc, char* argv[]) {
} options = {};
options.upload_gzip = true;
const option long_options[] = {
static constexpr option long_options[] = {
{"file", required_argument, nullptr, kOptionFile},
{"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip},
{"output", required_argument, nullptr, kOptionOutput},

View File

@ -85,7 +85,7 @@ int GenerateDumpMain(int argc, char* argv[]) {
} options = {};
options.suspend = true;
const option long_options[] = {
static constexpr option long_options[] = {
{"no-suspend", no_argument, nullptr, kOptionNoSuspend},
{"output", required_argument, nullptr, kOptionOutput},
{"help", no_argument, nullptr, kOptionHelp},

View File

@ -214,7 +214,7 @@ int CatchExceptionToolMain(int argc, char* argv[]) {
Options options = {};
const option long_options[] = {
static constexpr option long_options[] = {
{"file", required_argument, nullptr, kOptionFile},
{"mach-service", required_argument, nullptr, kOptionMachService},
{"persistent", no_argument, nullptr, kOptionPersistent},

View File

@ -106,8 +106,8 @@ struct ExceptionHandlerDescription {
std::string handler;
};
const char kHandlerNull[] = "NULL";
const char kHandlerBootstrapColon[] = "bootstrap:";
constexpr char kHandlerNull[] = "NULL";
constexpr char kHandlerBootstrapColon[] = "bootstrap:";
// Populates |description| based on a textual representation in
// |handler_string_ro|, returning true on success and false on failure (parse
@ -120,11 +120,11 @@ const char kHandlerBootstrapColon[] = "bootstrap:";
// SymbolicConstantsMach.
bool ParseHandlerString(const char* handler_string_ro,
ExceptionHandlerDescription* description) {
const char kTargetEquals[] = "target=";
const char kMaskEquals[] = "mask=";
const char kBehaviorEquals[] = "behavior=";
const char kFlavorEquals[] = "flavor=";
const char kHandlerEquals[] = "handler=";
static constexpr char kTargetEquals[] = "target=";
static constexpr char kMaskEquals[] = "mask=";
static constexpr char kBehaviorEquals[] = "behavior=";
static constexpr char kFlavorEquals[] = "flavor=";
static constexpr char kHandlerEquals[] = "handler=";
std::string handler_string(handler_string_ro);
char* handler_string_c = &handler_string[0];
@ -400,7 +400,7 @@ int ExceptionPortToolMain(int argc, char* argv[]) {
bool numeric;
} options = {};
const option long_options[] = {
static constexpr option long_options[] = {
{"set-handler", required_argument, nullptr, kOptionSetPort},
{"show-bootstrap", required_argument, nullptr, kOptionShowBootstrap},
{"pid", required_argument, nullptr, kOptionPid},

View File

@ -81,7 +81,7 @@ int OnDemandServiceToolMain(int argc, char* argv[]) {
std::vector<std::string> mach_services;
} options = {};
const option long_options[] = {
static constexpr option long_options[] = {
{"load", no_argument, nullptr, kOptionLoadJob},
{"unload", no_argument, nullptr, kOptionUnloadJob},
{"label", required_argument, nullptr, kOptionJobLabel},

View File

@ -84,7 +84,7 @@ int RunWithCrashpadMain(int argc, char* argv[]) {
kOptionVersion = -3,
};
const option long_options[] = {
static constexpr option long_options[] = {
{"handler", required_argument, nullptr, kOptionHandler},
{"annotation", required_argument, nullptr, kOptionAnnotation},
{"database", required_argument, nullptr, kOptionDatabase},

View File

@ -257,7 +257,7 @@ TEST(DelimitedFileReader, ReallyLongMultiLineFile) {
}
TEST(DelimitedFileReader, EmbeddedNUL) {
const char kString[] = "embedded\0NUL\n";
static constexpr char kString[] = "embedded\0NUL\n";
StringFile string_file;
string_file.SetString(std::string(kString, arraysize(kString) - 1));
DelimitedFileReader delimited_file_reader(&string_file);
@ -275,7 +275,7 @@ TEST(DelimitedFileReader, EmbeddedNUL) {
}
TEST(DelimitedFileReader, NULDelimiter) {
const char kString[] = "aa\0b\0ccc\0";
static constexpr char kString[] = "aa\0b\0ccc\0";
StringFile string_file;
string_file.SetString(std::string(kString, arraysize(kString) - 1));
DelimitedFileReader delimited_file_reader(&string_file);
@ -299,7 +299,8 @@ TEST(DelimitedFileReader, NULDelimiter) {
}
TEST(DelimitedFileReader, EdgeCases) {
const size_t kSizes[] = {4094, 4095, 4096, 4097, 8190, 8191, 8192, 8193};
static constexpr size_t kSizes[] =
{4094, 4095, 4096, 4097, 8190, 8191, 8192, 8193};
for (size_t index = 0; index < arraysize(kSizes); ++index) {
size_t size = kSizes[index];
SCOPED_TRACE(

View File

@ -45,11 +45,12 @@ using FileOffset = off_t;
//! \brief Scoped wrapper of a FileHandle.
using ScopedFileHandle = base::ScopedFD;
//! \brief The return value of read and write calls.
using FileOperationResult = ssize_t;
//! \brief A value that can never be a valid FileHandle.
const FileHandle kInvalidFileHandle = -1;
using FileOperationResult = ssize_t;
#elif defined(OS_WIN)
using FileHandle = HANDLE;
@ -109,19 +110,28 @@ enum class StdioStream {
namespace internal {
#if defined(OS_POSIX) || DOXYGEN
//! \brief The name of the native read function used by ReadFile().
//!
//! This value may be useful for logging.
//!
//! \sa kNativeWriteFunctionName
extern const char kNativeReadFunctionName[];
constexpr char kNativeReadFunctionName[] = "read";
//! \brief The name of the native write function used by WriteFile().
//!
//! This value may be useful for logging.
//!
//! \sa kNativeReadFunctionName
extern const char kNativeWriteFunctionName[];
constexpr char kNativeWriteFunctionName[] = "write";
#elif defined(OS_WIN)
constexpr char kNativeReadFunctionName[] = "ReadFile";
constexpr char kNativeWriteFunctionName[] = "WriteFile";
#endif
//! \brief The internal implementation of ReadFileExactly() and its wrappers.
//!

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