mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add TaskMemory, which can read another Mach task’s memory, and its test.
This also adds MachErrorMessage(), a test-only function that’s a dependency of TaskMemory’s test, and related test-only error message functions. TEST=util_test TaskMemory.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/438993002
This commit is contained in:
parent
859560f70d
commit
9f6d86742d
@ -19,3 +19,6 @@
|
|||||||
|
|
||||||
//! \namespace crashpad::internal
|
//! \namespace crashpad::internal
|
||||||
//! \brief The internal namespace, not for public use.
|
//! \brief The internal namespace, not for public use.
|
||||||
|
|
||||||
|
//! \namespace crashpad::test
|
||||||
|
//! \brief The testing namespace, for use in test code only.
|
||||||
|
112
util/mach/task_memory.cc
Normal file
112
util/mach/task_memory.cc
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Copyright 2014 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 "util/mach/task_memory.h"
|
||||||
|
|
||||||
|
#include <mach/mach_vm.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "base/logging.h"
|
||||||
|
#include "base/mac/mach_logging.h"
|
||||||
|
#include "base/mac/scoped_mach_vm.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
TaskMemory::TaskMemory(mach_port_t task) : task_(task) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) {
|
||||||
|
if (size == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mach_vm_address_t region_address = mach_vm_trunc_page(address);
|
||||||
|
mach_vm_size_t region_size =
|
||||||
|
mach_vm_round_page(address - region_address + size);
|
||||||
|
|
||||||
|
vm_offset_t region;
|
||||||
|
mach_msg_type_number_t region_count;
|
||||||
|
kern_return_t kr =
|
||||||
|
mach_vm_read(task_, region_address, region_size, ®ion, ®ion_count);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
MACH_LOG(WARNING, kr) << base::StringPrintf(
|
||||||
|
"mach_vm_read(0x%llx, 0x%llx)", region_address, region_size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DCHECK_EQ(region_count, region_size);
|
||||||
|
base::mac::ScopedMachVM region_owner(region, region_count);
|
||||||
|
|
||||||
|
const char* region_base = reinterpret_cast<const char*>(region);
|
||||||
|
memcpy(buffer, ®ion_base[address - region_address], size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) {
|
||||||
|
return ReadCStringInternal(address, false, 0, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address,
|
||||||
|
mach_vm_size_t size,
|
||||||
|
std::string* string) {
|
||||||
|
return ReadCStringInternal(address, true, size, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TaskMemory::ReadCStringInternal(mach_vm_address_t address,
|
||||||
|
bool has_size,
|
||||||
|
mach_vm_size_t size,
|
||||||
|
std::string* string) {
|
||||||
|
if (has_size) {
|
||||||
|
if (size == 0) {
|
||||||
|
string->clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size = PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string local_string;
|
||||||
|
mach_vm_address_t read_address = address;
|
||||||
|
do {
|
||||||
|
mach_vm_size_t read_length =
|
||||||
|
std::min(size, PAGE_SIZE - (read_address % PAGE_SIZE));
|
||||||
|
std::string read_string(read_length, '\0');
|
||||||
|
if (!Read(read_address, read_length, &read_string[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t terminator = read_string.find_first_of('\0');
|
||||||
|
if (terminator == std::string::npos) {
|
||||||
|
local_string.append(read_string);
|
||||||
|
} else {
|
||||||
|
local_string.append(read_string, 0, terminator);
|
||||||
|
string->swap(local_string);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_size) {
|
||||||
|
size -= read_length;
|
||||||
|
}
|
||||||
|
read_address = mach_vm_trunc_page(read_address + read_length);
|
||||||
|
} while ((!has_size || size > 0) && read_address > address);
|
||||||
|
|
||||||
|
LOG(WARNING) << base::StringPrintf("unterminated string at 0x%llx", address);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace crashpad
|
96
util/mach/task_memory.h
Normal file
96
util/mach/task_memory.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2014 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_UTIL_MACH_TASK_MEMORY_H_
|
||||||
|
#define CRASHPAD_UTIL_MACH_TASK_MEMORY_H_
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
|
||||||
|
//! \brief Accesses the memory of another Mach task.
|
||||||
|
class TaskMemory {
|
||||||
|
public:
|
||||||
|
//! \param[in] task A send right to the target task’s task port. This object
|
||||||
|
//! does not take ownership of the send right.
|
||||||
|
explicit TaskMemory(mach_port_t task);
|
||||||
|
|
||||||
|
~TaskMemory() {}
|
||||||
|
|
||||||
|
//! \brief Copies memory from the target task into a user-provided buffer in
|
||||||
|
//! the current task.
|
||||||
|
//!
|
||||||
|
//! \param[in] address The address, in the target task’s address space, of the
|
||||||
|
//! memory region to copy.
|
||||||
|
//! \param[in] size The size, in bytes, of the memory region to copy. \a
|
||||||
|
//! buffer must be at least this size.
|
||||||
|
//! \param[out] buffer The buffer into which the contents of the other task’s
|
||||||
|
//! memory will be copied.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success, with \a buffer filled appropriately. `false` on
|
||||||
|
//! failure, with a warning logged. Failures can occur, for example, when
|
||||||
|
//! encountering unmapped or unreadable pages.
|
||||||
|
bool Read(mach_vm_address_t address, size_t size, void* buffer);
|
||||||
|
|
||||||
|
//! \brief Reads a `NUL`-terminated C string from the target task into a
|
||||||
|
//! string in the current task.
|
||||||
|
//!
|
||||||
|
//! The length of the string need not be known ahead of time. This method will
|
||||||
|
//! read contiguous memory until a `NUL` terminator is found.
|
||||||
|
//!
|
||||||
|
//! \param[in] address The address, in the target task’s address space, of the
|
||||||
|
//! string to copy.
|
||||||
|
//! \param[out] string The string read from the other task.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success, with \a string set appropriately. `false` on
|
||||||
|
//! failure, with a warning logged. Failures can occur, for example, when
|
||||||
|
//! encountering unmapped or unreadable pages.
|
||||||
|
bool ReadCString(mach_vm_address_t address, std::string* string);
|
||||||
|
|
||||||
|
//! \brief Reads a `NUL`-terminated C string from the target task into a
|
||||||
|
//! string in the current task.
|
||||||
|
//!
|
||||||
|
//! \param[in] address The address, in the target task’s address space, of the
|
||||||
|
//! string to copy.
|
||||||
|
//! \param[in] size The maximum number of bytes to read. The string is
|
||||||
|
//! required to be `NUL`-terminated within this many bytes.
|
||||||
|
//! \param[out] string The string read from the other task.
|
||||||
|
//!
|
||||||
|
//! \return `true` on success, with \a string set appropriately. `false` on
|
||||||
|
//! failure, with a warning logged. Failures can occur, for example, when
|
||||||
|
//! a `NUL` terminator is not found within \a size bytes, or when
|
||||||
|
//! encountering unmapped or unreadable pages.
|
||||||
|
bool ReadCStringSizeLimited(mach_vm_address_t address,
|
||||||
|
mach_vm_size_t size,
|
||||||
|
std::string* string);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// The common internal implementation shared by the ReadCString*() methods.
|
||||||
|
bool ReadCStringInternal(mach_vm_address_t address,
|
||||||
|
bool has_size,
|
||||||
|
mach_vm_size_t size,
|
||||||
|
std::string* string);
|
||||||
|
|
||||||
|
mach_port_t task_; // weak
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TaskMemory);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_MACH_TASK_MEMORY_H_
|
386
util/mach/task_memory_test.cc
Normal file
386
util/mach/task_memory_test.cc
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
// Copyright 2014 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 "util/mach/task_memory.h"
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "base/mac/scoped_mach_vm.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "util/test/mac/mach_errors.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace crashpad;
|
||||||
|
using namespace crashpad::test;
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadSelf) {
|
||||||
|
vm_address_t address = 0;
|
||||||
|
const vm_size_t kSize = 4 * PAGE_SIZE;
|
||||||
|
kern_return_t kr =
|
||||||
|
vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
|
||||||
|
base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
|
||||||
|
|
||||||
|
char* region = reinterpret_cast<char*>(address);
|
||||||
|
for (size_t index = 0; index < kSize; ++index) {
|
||||||
|
region[index] = (index % 256) ^ ((index >> 8) % 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result(kSize, '\0');
|
||||||
|
|
||||||
|
// Ensure that the entire region can be read.
|
||||||
|
ASSERT_TRUE(memory.Read(address, kSize, &result[0]));
|
||||||
|
EXPECT_EQ(0, memcmp(region, &result[0], kSize));
|
||||||
|
|
||||||
|
// Ensure that a read of length 0 succeeds and doesn’t touch the result.
|
||||||
|
result.assign(kSize, '\0');
|
||||||
|
std::string zeroes = result;
|
||||||
|
ASSERT_TRUE(memory.Read(address, 0, &result[0]));
|
||||||
|
EXPECT_EQ(zeroes, result);
|
||||||
|
|
||||||
|
// Ensure that a read starting at an unaligned address works.
|
||||||
|
ASSERT_TRUE(memory.Read(address + 1, kSize - 1, &result[0]));
|
||||||
|
EXPECT_EQ(0, memcmp(region + 1, &result[0], kSize - 1));
|
||||||
|
|
||||||
|
// Ensure that a read ending at an unaligned address works.
|
||||||
|
ASSERT_TRUE(memory.Read(address, kSize - 1, &result[0]));
|
||||||
|
EXPECT_EQ(0, memcmp(region, &result[0], kSize - 1));
|
||||||
|
|
||||||
|
// Ensure that a read starting and ending at unaligned addresses works.
|
||||||
|
ASSERT_TRUE(memory.Read(address + 1, kSize - 2, &result[0]));
|
||||||
|
EXPECT_EQ(0, memcmp(region + 1, &result[0], kSize - 2));
|
||||||
|
|
||||||
|
// Ensure that a read of exactly one page works.
|
||||||
|
ASSERT_TRUE(memory.Read(address + PAGE_SIZE, PAGE_SIZE, &result[0]));
|
||||||
|
EXPECT_EQ(0, memcmp(region + PAGE_SIZE, &result[0], PAGE_SIZE));
|
||||||
|
|
||||||
|
// Ensure that a read of a single byte works.
|
||||||
|
ASSERT_TRUE(memory.Read(address + 2, 1, &result[0]));
|
||||||
|
EXPECT_EQ(region[2], result[0]);
|
||||||
|
|
||||||
|
// Ensure that a read of length zero works and doesn’t touch the data.
|
||||||
|
result[0] = 'M';
|
||||||
|
ASSERT_TRUE(memory.Read(address + 3, 0, &result[0]));
|
||||||
|
EXPECT_EQ('M', result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadSelfUnmapped) {
|
||||||
|
vm_address_t address = 0;
|
||||||
|
const vm_size_t kSize = 2 * PAGE_SIZE;
|
||||||
|
kern_return_t kr =
|
||||||
|
vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
|
||||||
|
base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
|
||||||
|
|
||||||
|
char* region = reinterpret_cast<char*>(address);
|
||||||
|
for (size_t index = 0; index < kSize; ++index) {
|
||||||
|
// Don’t include any NUL bytes, because ReadCString stops when it encounters
|
||||||
|
// a NUL.
|
||||||
|
region[index] = (index % 255) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kr = vm_protect(
|
||||||
|
mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_protect");
|
||||||
|
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result(kSize, '\0');
|
||||||
|
|
||||||
|
EXPECT_FALSE(memory.Read(address, kSize, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + 1, kSize - 1, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + PAGE_SIZE, 1, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + PAGE_SIZE - 1, 2, &result[0]));
|
||||||
|
EXPECT_TRUE(memory.Read(address, PAGE_SIZE, &result[0]));
|
||||||
|
EXPECT_TRUE(memory.Read(address + PAGE_SIZE - 1, 1, &result[0]));
|
||||||
|
|
||||||
|
// Repeat the test with an unmapped page instead of an unreadable one. This
|
||||||
|
// portion of the test may be flaky in the presence of other threads, if
|
||||||
|
// another thread maps something in the region that is deallocated here.
|
||||||
|
kr = vm_deallocate(mach_task_self(), address + PAGE_SIZE, PAGE_SIZE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_deallocate");
|
||||||
|
vm_owner.reset(address, PAGE_SIZE);
|
||||||
|
|
||||||
|
EXPECT_FALSE(memory.Read(address, kSize, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + 1, kSize - 1, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + PAGE_SIZE, 1, &result[0]));
|
||||||
|
EXPECT_FALSE(memory.Read(address + PAGE_SIZE - 1, 2, &result[0]));
|
||||||
|
EXPECT_TRUE(memory.Read(address, PAGE_SIZE, &result[0]));
|
||||||
|
EXPECT_TRUE(memory.Read(address + PAGE_SIZE - 1, 1, &result[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function consolidates the cast from a char* to mach_vm_address_t in one
|
||||||
|
// location when reading from the current task.
|
||||||
|
bool ReadCStringSelf(TaskMemory* memory,
|
||||||
|
const char* pointer,
|
||||||
|
std::string* result) {
|
||||||
|
return memory->ReadCString(reinterpret_cast<mach_vm_address_t>(pointer),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSelf) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
const char kConstCharEmpty[] = "";
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharEmpty, &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharEmpty, result);
|
||||||
|
|
||||||
|
const char kConstCharShort[] = "A short const char[]";
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, kConstCharShort, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharShort, result);
|
||||||
|
|
||||||
|
static const char kStaticConstCharEmpty[] = "";
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharEmpty, &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharEmpty, result);
|
||||||
|
|
||||||
|
static const char kStaticConstCharShort[] = "A short static const char[]";
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, kStaticConstCharShort, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharShort, result);
|
||||||
|
|
||||||
|
std::string string_short("A short std::string in a function");
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, &string_short[0], &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(string_short, result);
|
||||||
|
|
||||||
|
std::string string_long;
|
||||||
|
const size_t kStringLongSize = 4 * PAGE_SIZE;
|
||||||
|
for (size_t index = 0; index < kStringLongSize; ++index) {
|
||||||
|
// Don’t include any NUL bytes, because ReadCString stops when it encounters
|
||||||
|
// a NUL.
|
||||||
|
string_long.append(1, (index % 255) + 1);
|
||||||
|
}
|
||||||
|
ASSERT_EQ(kStringLongSize, string_long.size());
|
||||||
|
ASSERT_TRUE(ReadCStringSelf(&memory, &string_long[0], &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStringLongSize, result.size());
|
||||||
|
EXPECT_EQ(string_long, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSelfUnmapped) {
|
||||||
|
vm_address_t address = 0;
|
||||||
|
const vm_size_t kSize = 2 * PAGE_SIZE;
|
||||||
|
kern_return_t kr =
|
||||||
|
vm_allocate(mach_task_self(), &address, kSize, VM_FLAGS_ANYWHERE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_allocate");
|
||||||
|
base::mac::ScopedMachVM vm_owner(address, mach_vm_round_page(kSize));
|
||||||
|
|
||||||
|
char* region = reinterpret_cast<char*>(address);
|
||||||
|
for (size_t index = 0; index < kSize; ++index) {
|
||||||
|
// Don’t include any NUL bytes, because ReadCString stops when it encounters
|
||||||
|
// a NUL.
|
||||||
|
region[index] = (index % 255) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
kr = vm_protect(
|
||||||
|
mach_task_self(), address + PAGE_SIZE, PAGE_SIZE, FALSE, VM_PROT_NONE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_protect");
|
||||||
|
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
EXPECT_FALSE(memory.ReadCString(address, &result));
|
||||||
|
|
||||||
|
// Make sure that if the string is NUL-terminated within the mapped memory
|
||||||
|
// region, it can be read properly.
|
||||||
|
char terminator_or_not = '\0';
|
||||||
|
std::swap(region[PAGE_SIZE - 1], terminator_or_not);
|
||||||
|
ASSERT_TRUE(memory.ReadCString(address, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(PAGE_SIZE - 1u, result.size());
|
||||||
|
EXPECT_EQ(region, result);
|
||||||
|
|
||||||
|
// Repeat the test with an unmapped page instead of an unreadable one. This
|
||||||
|
// portion of the test may be flaky in the presence of other threads, if
|
||||||
|
// another thread maps something in the region that is deallocated here.
|
||||||
|
std::swap(region[PAGE_SIZE - 1], terminator_or_not);
|
||||||
|
kr = vm_deallocate(mach_task_self(), address + PAGE_SIZE, PAGE_SIZE);
|
||||||
|
ASSERT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_deallocate");
|
||||||
|
vm_owner.reset(address, PAGE_SIZE);
|
||||||
|
|
||||||
|
EXPECT_FALSE(memory.ReadCString(address, &result));
|
||||||
|
|
||||||
|
// Clear the result before testing that the string can be read. This makes
|
||||||
|
// sure that the result is actually filled in, because it already contains the
|
||||||
|
// expected value from the tests above.
|
||||||
|
result.clear();
|
||||||
|
std::swap(region[PAGE_SIZE - 1], terminator_or_not);
|
||||||
|
ASSERT_TRUE(memory.ReadCString(address, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(PAGE_SIZE - 1u, result.size());
|
||||||
|
EXPECT_EQ(region, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function consolidates the cast from a char* to mach_vm_address_t in one
|
||||||
|
// location when reading from the current task.
|
||||||
|
bool ReadCStringSizeLimitedSelf(TaskMemory* memory,
|
||||||
|
const char* pointer,
|
||||||
|
size_t size,
|
||||||
|
std::string* result) {
|
||||||
|
return memory->ReadCStringSizeLimited(
|
||||||
|
reinterpret_cast<mach_vm_address_t>(pointer), size, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_ConstCharEmpty) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
const char kConstCharEmpty[] = "";
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, kConstCharEmpty, arraysize(kConstCharEmpty), &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharEmpty, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, kConstCharEmpty, arraysize(kConstCharEmpty) + 1, &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharEmpty, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory, kConstCharEmpty, 0, &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharEmpty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_ConstCharShort) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
const char kConstCharShort[] = "A short const char[]";
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, kConstCharShort, arraysize(kConstCharShort), &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharShort, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, kConstCharShort, arraysize(kConstCharShort) + 1, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kConstCharShort, result);
|
||||||
|
|
||||||
|
ASSERT_FALSE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, kConstCharShort, arraysize(kConstCharShort) - 1, &result));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharEmpty) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
static const char kStaticConstCharEmpty[] = "";
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
|
||||||
|
kStaticConstCharEmpty,
|
||||||
|
arraysize(kStaticConstCharEmpty),
|
||||||
|
&result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharEmpty, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
|
||||||
|
kStaticConstCharEmpty,
|
||||||
|
arraysize(kStaticConstCharEmpty) + 1,
|
||||||
|
&result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharEmpty, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(
|
||||||
|
ReadCStringSizeLimitedSelf(&memory, kStaticConstCharEmpty, 0, &result));
|
||||||
|
EXPECT_TRUE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharEmpty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_StaticConstCharShort) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
static const char kStaticConstCharShort[] = "A short static const char[]";
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
|
||||||
|
kStaticConstCharShort,
|
||||||
|
arraysize(kStaticConstCharShort),
|
||||||
|
&result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharShort, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(&memory,
|
||||||
|
kStaticConstCharShort,
|
||||||
|
arraysize(kStaticConstCharShort) + 1,
|
||||||
|
&result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStaticConstCharShort, result);
|
||||||
|
|
||||||
|
ASSERT_FALSE(ReadCStringSizeLimitedSelf(&memory,
|
||||||
|
kStaticConstCharShort,
|
||||||
|
arraysize(kStaticConstCharShort) - 1,
|
||||||
|
&result));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_StringShort) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
std::string string_short("A short std::string in a function");
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_short[0], string_short.size() + 1, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(string_short, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_short[0], string_short.size() + 2, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(string_short, result);
|
||||||
|
|
||||||
|
ASSERT_FALSE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_short[0], string_short.size(), &result));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TaskMemory, ReadCStringSizeLimited_StringLong) {
|
||||||
|
TaskMemory memory(mach_task_self());
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
std::string string_long;
|
||||||
|
const size_t kStringLongSize = 4 * PAGE_SIZE;
|
||||||
|
for (size_t index = 0; index < kStringLongSize; ++index) {
|
||||||
|
// Don’t include any NUL bytes, because ReadCString stops when it encounters
|
||||||
|
// a NUL.
|
||||||
|
string_long.append(1, (index % 255) + 1);
|
||||||
|
}
|
||||||
|
ASSERT_EQ(kStringLongSize, string_long.size());
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_long[0], string_long.size() + 1, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStringLongSize, result.size());
|
||||||
|
EXPECT_EQ(string_long, result);
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
ASSERT_TRUE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_long[0], string_long.size() + 2, &result));
|
||||||
|
EXPECT_FALSE(result.empty());
|
||||||
|
EXPECT_EQ(kStringLongSize, result.size());
|
||||||
|
EXPECT_EQ(string_long, result);
|
||||||
|
|
||||||
|
ASSERT_FALSE(ReadCStringSizeLimitedSelf(
|
||||||
|
&memory, &string_long[0], string_long.size(), &result));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
38
util/test/errors.cc
Normal file
38
util/test/errors.cc
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2014 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 "util/test/errors.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "base/safe_strerror_posix.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
std::string ErrnoMessage(int err, const std::string& base) {
|
||||||
|
return base::StringPrintf("%s%s%s (%d)",
|
||||||
|
base.c_str(),
|
||||||
|
base.empty() ? "" : ": ",
|
||||||
|
safe_strerror(errno).c_str(),
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ErrnoMessage(const std::string& base) {
|
||||||
|
return ErrnoMessage(errno, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
71
util/test/errors.h
Normal file
71
util/test/errors.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2014 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_UTIL_TEST_ERRORS_H_
|
||||||
|
#define CRASHPAD_UTIL_TEST_ERRORS_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// These functions format messages in a similar way to the PLOG and PCHECK
|
||||||
|
// family of logging macros in base/logging.h. They exist to interoperate with
|
||||||
|
// gtest assertions, which don’t interoperate with logging but can be streamed
|
||||||
|
// to.
|
||||||
|
//
|
||||||
|
// Where non-test code could do:
|
||||||
|
// PCHECK(rv == 0) << "close";
|
||||||
|
// gtest-based test code can do:
|
||||||
|
// EXPECT_EQ(0, rv) << ErrnoMessage("close");
|
||||||
|
|
||||||
|
//! \brief Formats an error message using an `errno` value.
|
||||||
|
//!
|
||||||
|
//! The returned string will combine the \a base string, if supplied, with a
|
||||||
|
//! a textual and numeric description of the error.
|
||||||
|
//!
|
||||||
|
//! The message is formatted using `strerror()`. \a err may be `0` or outside of
|
||||||
|
//! the range of known error codes, and the message returned will contain the
|
||||||
|
//! string that `strerror()` uses in these cases.
|
||||||
|
//!
|
||||||
|
//! \param[in] err The error code, usable as an `errno` value.
|
||||||
|
//! \param[in] base A string to prepend to the error description.
|
||||||
|
//!
|
||||||
|
//! \return A string of the format `"Operation not permitted (1)"` if \a err has
|
||||||
|
//! the value `EPERM` on a system where this is defined to be `1`. If \a
|
||||||
|
//! base is not empty, it will be prepended to this string, separated by a
|
||||||
|
//! colon.
|
||||||
|
std::string ErrnoMessage(int err, const std::string& base = std::string());
|
||||||
|
|
||||||
|
//! \brief Formats an error message using `errno`.
|
||||||
|
//!
|
||||||
|
//! The returned string will combine the \a base string, if supplied, with a
|
||||||
|
//! a textual and numeric description of the error.
|
||||||
|
//!
|
||||||
|
//! The message is formatted using `strerror()`. `errno` may be `0` or outside
|
||||||
|
//! of the range of known error codes, and the message returned will contain the
|
||||||
|
//! string that `strerror()` uses in these cases.
|
||||||
|
//!
|
||||||
|
//! \param[in] base A string to prepend to the error description.
|
||||||
|
//!
|
||||||
|
//! \return A string of the format `"Operation not permitted (1)"` if `errno`
|
||||||
|
//! has the value `EPERM` on a system where this is defined to be `1`. If
|
||||||
|
//! \a base is not empty, it will be prepended to this string, separated by
|
||||||
|
//! a colon.
|
||||||
|
std::string ErrnoMessage(const std::string& base = std::string());
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_TEST_ERRORS_H_
|
78
util/test/mac/mach_errors.cc
Normal file
78
util/test/mac/mach_errors.cc
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright 2014 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 "util/test/mac/mach_errors.h"
|
||||||
|
|
||||||
|
#include <servers/bootstrap.h>
|
||||||
|
|
||||||
|
#include "base/safe_strerror_posix.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string FormatBase(const std::string& base) {
|
||||||
|
if (base.empty()) {
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return base::StringPrintf("%s: ", base.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FormatMachErrorNumber(mach_error_t mach_err) {
|
||||||
|
// For the os/kern subsystem, give the error number in decimal as in
|
||||||
|
// <mach/kern_return.h>. Otherwise, give it in hexadecimal to make it easier
|
||||||
|
// to visualize the various bits. See <mach/error.h>.
|
||||||
|
if (mach_err >= 0 && mach_err < KERN_RETURN_MAX) {
|
||||||
|
return base::StringPrintf(" (%d)", mach_err);
|
||||||
|
}
|
||||||
|
return base::StringPrintf(" (0x%08x)", mach_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
std::string MachErrorMessage(mach_error_t mach_err, const std::string& base) {
|
||||||
|
return base::StringPrintf("%s%s%s",
|
||||||
|
FormatBase(base).c_str(),
|
||||||
|
mach_error_string(mach_err),
|
||||||
|
FormatMachErrorNumber(mach_err).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BootstrapErrorMessage(kern_return_t bootstrap_err,
|
||||||
|
const std::string& base) {
|
||||||
|
switch (bootstrap_err) {
|
||||||
|
case BOOTSTRAP_SUCCESS:
|
||||||
|
case BOOTSTRAP_NOT_PRIVILEGED:
|
||||||
|
case BOOTSTRAP_NAME_IN_USE:
|
||||||
|
case BOOTSTRAP_UNKNOWN_SERVICE:
|
||||||
|
case BOOTSTRAP_SERVICE_ACTIVE:
|
||||||
|
case BOOTSTRAP_BAD_COUNT:
|
||||||
|
case BOOTSTRAP_NO_MEMORY:
|
||||||
|
case BOOTSTRAP_NO_CHILDREN:
|
||||||
|
// Show known bootstrap errors in decimal because that's how they're
|
||||||
|
// defined in <servers/bootstrap.h>.
|
||||||
|
return base::StringPrintf("%s%s (%d)",
|
||||||
|
FormatBase(base).c_str(),
|
||||||
|
bootstrap_strerror(bootstrap_err),
|
||||||
|
bootstrap_err);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return MachErrorMessage(bootstrap_err, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
70
util/test/mac/mach_errors.h
Normal file
70
util/test/mac/mach_errors.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2014 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_UTIL_TEST_MAC_MACH_ERRORS_H_
|
||||||
|
#define CRASHPAD_UTIL_TEST_MAC_MACH_ERRORS_H_
|
||||||
|
|
||||||
|
#include <mach/mach.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
// These functions format messages in a similar way to the logging macros in
|
||||||
|
// base/mac/mach_logging.h. They exist to interoperate with gtest assertions,
|
||||||
|
// which don’t interoperate with logging but can be streamed to.
|
||||||
|
//
|
||||||
|
// Where non-test code could do:
|
||||||
|
// MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_deallocate";
|
||||||
|
// gtest-based test code can do:
|
||||||
|
// EXPECT_EQ(KERN_SUCCESS, kr) << MachErrorMessage(kr, "vm_deallocate");
|
||||||
|
|
||||||
|
//! \brief Formats a Mach error message.
|
||||||
|
//!
|
||||||
|
//! The returned string will combine the \a base string, if supplied, with a
|
||||||
|
//! a textual and numeric description of the error.
|
||||||
|
//!
|
||||||
|
//! \param[in] mach_err The Mach error code, which may be a `kern_return_t` or
|
||||||
|
//! related type.
|
||||||
|
//! \param[in] base A string to prepend to the error description.
|
||||||
|
//!
|
||||||
|
//! \return A string of the format `"(os/kern) invalid address (1)"` if \a
|
||||||
|
//! mach_err has the value `KERN_INVALID_ADDRESS` on a system where this is
|
||||||
|
//! defined to be 1. If \a base is not empty, it will be prepended to this
|
||||||
|
//! string, separated by a colon.
|
||||||
|
std::string MachErrorMessage(mach_error_t mach_err,
|
||||||
|
const std::string& base = std::string());
|
||||||
|
|
||||||
|
//! \brief Formats a bootstrap error message.
|
||||||
|
//!
|
||||||
|
//! The returned string will combine the \a base string, if supplied, with a
|
||||||
|
//! a textual and numeric description of the error.
|
||||||
|
//!
|
||||||
|
//! \param[in] bootstrap_err The bootstrap error code.
|
||||||
|
//! \param[in] base A string to prepend to the error description.
|
||||||
|
//!
|
||||||
|
//! \return A string of the format `"Permission denied (1100)"` if \a
|
||||||
|
//! bootstrap_err has the value `BOOTSTRAP_NOT_PRIVILEGED` on a system where
|
||||||
|
//! this is defined to be 1100. If \a base is not empty, it will be
|
||||||
|
//! prepended to this string, separated by a colon. If \a bootstrap_err is
|
||||||
|
//! not a valid bootstrap error code, it will be interpreted as a Mach error
|
||||||
|
//! code in the manner of MachErrorMessage().
|
||||||
|
std::string BootstrapErrorMessage(kern_return_t bootstrap_err,
|
||||||
|
const std::string& base = std::string());
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace crashpad
|
||||||
|
|
||||||
|
#endif // CRASHPAD_UTIL_TEST_MAC_MACH_ERRORS_H_
|
@ -32,6 +32,8 @@
|
|||||||
'file/file_writer.h',
|
'file/file_writer.h',
|
||||||
'file/string_file_writer.cc',
|
'file/string_file_writer.cc',
|
||||||
'file/string_file_writer.h',
|
'file/string_file_writer.h',
|
||||||
|
'mach/task_memory.cc',
|
||||||
|
'mach/task_memory.h',
|
||||||
'misc/uuid.cc',
|
'misc/uuid.cc',
|
||||||
'misc/uuid.h',
|
'misc/uuid.h',
|
||||||
'stdlib/cxx.h',
|
'stdlib/cxx.h',
|
||||||
@ -39,11 +41,30 @@
|
|||||||
'stdlib/strlcpy.h',
|
'stdlib/strlcpy.h',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'target_name': 'util_test_lib',
|
||||||
|
'type': 'static_library',
|
||||||
|
'dependencies': [
|
||||||
|
'../compat/compat.gyp:compat',
|
||||||
|
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
||||||
|
'util',
|
||||||
|
],
|
||||||
|
'include_dirs': [
|
||||||
|
'..',
|
||||||
|
],
|
||||||
|
'sources': [
|
||||||
|
'test/errors.cc',
|
||||||
|
'test/errors.h',
|
||||||
|
'test/mac/mach_errors.cc',
|
||||||
|
'test/mac/mach_errors.h',
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
'target_name': 'util_test',
|
'target_name': 'util_test',
|
||||||
'type': 'executable',
|
'type': 'executable',
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'util',
|
'util',
|
||||||
|
'util_test_lib',
|
||||||
'../compat/compat.gyp:compat',
|
'../compat/compat.gyp:compat',
|
||||||
'../third_party/gtest/gtest.gyp:gtest',
|
'../third_party/gtest/gtest.gyp:gtest',
|
||||||
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
'../third_party/mini_chromium/mini_chromium/base/base.gyp:base',
|
||||||
@ -54,6 +75,7 @@
|
|||||||
'sources': [
|
'sources': [
|
||||||
'../third_party/gtest/gtest/src/gtest_main.cc',
|
'../third_party/gtest/gtest/src/gtest_main.cc',
|
||||||
'file/string_file_writer_test.cc',
|
'file/string_file_writer_test.cc',
|
||||||
|
'mach/task_memory_test.cc',
|
||||||
'misc/uuid_test.cc',
|
'misc/uuid_test.cc',
|
||||||
'stdlib/strlcpy_test.cc',
|
'stdlib/strlcpy_test.cc',
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user