Provide a properly-typed ExpectedSizeForVersion() for types that need it

Rather than declaring ExpectedSizeForVersion() for all process_types
types and providing a default NOTREACHED() implementation, this only
declares it for process_types that request it by stating
PROCESS_TYPE_STRUCT_VERSIONED() in their proctype definition. This also
allows the argument to have the correct type, matching the type of the
struct’s version field.

TEST=crashpad_snapshot_test
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/1274663005 .
This commit is contained in:
Mark Mentovai 2015-08-07 16:31:27 -04:00
parent 6083a2706d
commit 402bb216fb
5 changed files with 128 additions and 78 deletions

View File

@ -17,7 +17,6 @@
#include <string.h>
#include <uuid/uuid.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "snapshot/mac/process_types/internal.h"
#include "util/mach/task_memory.h"
@ -83,68 +82,58 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
// operates on each member in the struct.
#define PROCESS_TYPE_STRUCT_IMPLEMENT 1
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
namespace crashpad { \
namespace process_types { \
\
/* static */ \
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name<internal::Traits32>::Size(); \
} else { \
return internal::struct_name<internal::Traits64>::Size(); \
} \
} \
\
/* static */ \
size_t struct_name::ExpectedSizeForVersion(ProcessReader* process_reader, \
uint64_t version) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name< \
internal::Traits32>::ExpectedSizeForVersion(version); \
} else { \
return internal::struct_name< \
internal::Traits64>::ExpectedSizeForVersion(version); \
} \
} \
\
/* static */ \
bool struct_name::ReadInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
if (!process_reader->Is64Bit()) { \
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
process_reader, address, generic); \
} else { \
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
process_reader, address, generic); \
} \
} \
\
/* static */ \
template <typename T> \
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
T specific; \
if (!specific.Read(process_reader, address)) { \
return false; \
} \
specific.GenericizeInto(generic, &generic->size_); \
return true; \
} \
\
namespace internal { \
\
template <typename Traits> \
void struct_name<Traits>::GenericizeInto( \
process_types::struct_name* generic, \
size_t* specific_size) { \
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \
namespace crashpad { \
namespace process_types { \
\
/* static */ \
size_t struct_name::ExpectedSize(ProcessReader* process_reader) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name<internal::Traits32>::Size(); \
} else { \
return internal::struct_name<internal::Traits64>::Size(); \
} \
} \
\
/* static */ \
bool struct_name::ReadInto(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
if (!process_reader->Is64Bit()) { \
return ReadIntoInternal<internal::struct_name<internal::Traits32> >( \
process_reader, address, generic); \
} else { \
return ReadIntoInternal<internal::struct_name<internal::Traits64> >( \
process_reader, address, generic); \
} \
} \
\
/* static */ \
template <typename T> \
bool struct_name::ReadIntoInternal(ProcessReader* process_reader, \
mach_vm_address_t address, \
struct_name* generic) { \
T specific; \
if (!specific.Read(process_reader, address)) { \
return false; \
} \
specific.GenericizeInto(generic, &generic->size_); \
return true; \
} \
\
namespace internal { \
\
template <typename Traits> \
void struct_name<Traits>::GenericizeInto( \
process_types::struct_name* generic, \
size_t* specific_size) { \
*specific_size = Size();
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
Assign(&generic->member_name, member_name);
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field)
#define PROCESS_TYPE_STRUCT_END(struct_name) \
} \
} /* namespace internal */ \
@ -155,6 +144,7 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_IMPLEMENT
@ -185,12 +175,15 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...)
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field)
#define PROCESS_TYPE_STRUCT_END(struct_name)
#include "snapshot/mac/process_types/all.proctype"
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO
@ -216,12 +209,6 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
address, sizeof(struct_name<Traits>[count]), specific); \
} \
\
/* static */ \
template <typename Traits> \
size_t struct_name<Traits>::ExpectedSizeForVersion(uint64_t version) { \
NOTREACHED(); \
return 0; \
} \
} /* namespace internal */ \
\
/* static */ \
@ -261,11 +248,57 @@ inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) {
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...)
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field)
#define PROCESS_TYPE_STRUCT_END(struct_name)
#include "snapshot/mac/process_types/all.proctype"
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY
// Implement the generic crashpad::process_types::struct_name
// ExpectedSizeForVersion(), which delegates to the templatized
// ExpectedSizeForVersion(), which returns the expected size of a versioned
// structure given a version parameter. This is only implemented for structures
// that use PROCESS_TYPE_STRUCT_VERSIONED(), and implementations of the internal
// templatized functions must be provided in
// snapshot/mac/process_types/custom.cc.
#define PROCESS_TYPE_STRUCT_IMPLEMENT_VERSIONED 1
#define PROCESS_TYPE_STRUCT_BEGIN(struct_name)
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...)
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field) \
namespace crashpad { \
namespace process_types { \
\
/* static */ \
size_t struct_name::ExpectedSizeForVersion( \
ProcessReader* process_reader, \
decltype(struct_name::version_field) version) { \
if (!process_reader->Is64Bit()) { \
return internal::struct_name< \
internal::Traits32>::ExpectedSizeForVersion(version); \
} else { \
return internal::struct_name< \
internal::Traits64>::ExpectedSizeForVersion(version); \
} \
} \
\
} /* namespace process_types */ \
} /* namespace crashpad */
#define PROCESS_TYPE_STRUCT_END(struct_name)
#include "snapshot/mac/process_types/all.proctype"
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_IMPLEMENT_VERSIONED

View File

@ -86,16 +86,18 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
* on the process bitness. This can be used prior to reading any data \
* from a process. */ \
static size_t ExpectedSize(ProcessReader* process_reader); \
\
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
member_type member_name __VA_ARGS__;
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field) \
/* Similar to ExpectedSize(), but computes the expected size of a \
* structure based on the process bitness and a custom value, such as a \
* structure version number. This can be used prior to reading any data \
* from a process. */ \
static size_t ExpectedSizeForVersion(ProcessReader* process_reader, \
uint64_t version);
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
member_type member_name __VA_ARGS__;
static size_t ExpectedSizeForVersion( \
ProcessReader* process_reader, \
decltype(struct_name::version_field) version);
#define PROCESS_TYPE_STRUCT_END(struct_name) \
private: \
@ -122,6 +124,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_DECLARE
@ -131,7 +134,6 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
// shared with the generic declaration above because both the generic and
// templatized specific structs need all of the struct members declared.
//
//
// GenericizeInto() translates a struct from the representation used in the
// remote process into the generic form.
#define PROCESS_TYPE_STRUCT_DECLARE_INTERNAL 1
@ -150,8 +152,8 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
using UIntPtr = typename Traits::UIntPtr; \
using Reserved64Only = typename Traits::Reserved64Only; \
\
/* Read(), ReadArrayInto(), Size(), and ExpectedSizeForVersion() are as in \
* the generic user-visible struct above. */ \
/* Read(), ReadArrayInto(), and Size() are as in the generic user-visible \
* struct above. */ \
bool Read(ProcessReader* process_reader, mach_vm_address_t address) { \
return ReadInto(process_reader, address, this); \
} \
@ -160,7 +162,6 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
size_t count, \
struct_name<Traits>* specific); \
static size_t Size() { return sizeof(struct_name<Traits>); } \
static size_t ExpectedSizeForVersion(uint64_t version); \
\
/* Translates a struct from the representation used in the remote process \
* into the generic form. */ \
@ -170,6 +171,12 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
#define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) \
member_type member_name __VA_ARGS__;
#define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field) \
/* ExpectedSizeForVersion() is as in the generic user-visible struct \
* above. */ \
static size_t ExpectedSizeForVersion( \
decltype(struct_name::version_field) version);
#define PROCESS_TYPE_STRUCT_END(struct_name) \
private: \
/* ReadInto() is as in the generic user-visible struct above. */ \
@ -185,6 +192,7 @@ DECLARE_PROCESS_TYPE_TRAITS_CLASS(Generic, 64)
#undef PROCESS_TYPE_STRUCT_BEGIN
#undef PROCESS_TYPE_STRUCT_MEMBER
#undef PROCESS_TYPE_STRUCT_VERSIONED
#undef PROCESS_TYPE_STRUCT_END
#undef PROCESS_TYPE_STRUCT_DECLARE_INTERNAL

View File

@ -41,6 +41,7 @@
PROCESS_TYPE_STRUCT_BEGIN(crashreporter_annotations_t)
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, version) // unsigned long
PROCESS_TYPE_STRUCT_VERSIONED(crashreporter_annotations_t, version)
// Version 4 (Mac OS X 10.7)
PROCESS_TYPE_STRUCT_MEMBER(uint64_t, message) // char*

View File

@ -24,6 +24,8 @@ namespace crashpad {
namespace process_types {
namespace internal {
namespace {
template <typename T>
bool ReadIntoVersioned(ProcessReader* process_reader,
mach_vm_address_t address,
@ -51,9 +53,12 @@ bool ReadIntoVersioned(ProcessReader* process_reader,
return true;
}
} // namespace
// static
template <typename Traits>
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(uint64_t version) {
size_t dyld_all_image_infos<Traits>::ExpectedSizeForVersion(
decltype(dyld_all_image_infos<Traits>::version) version) {
if (version >= 14) {
return sizeof(dyld_all_image_infos<Traits>);
}
@ -108,7 +113,7 @@ bool dyld_all_image_infos<Traits>::ReadInto(
// static
template <typename Traits>
size_t crashreporter_annotations_t<Traits>::ExpectedSizeForVersion(
uint64_t version) {
decltype(crashreporter_annotations_t<Traits>::version) version) {
if (version >= 5) {
return sizeof(crashreporter_annotations_t<Traits>);
}
@ -127,16 +132,18 @@ bool crashreporter_annotations_t<Traits>::ReadInto(
return ReadIntoVersioned(process_reader, address, specific);
}
// Explicit template instantiation of the above.
#define PROCESS_TYPE_FLAVOR_TRAITS(lp_bits) \
template size_t \
dyld_all_image_infos<Traits##lp_bits>::ExpectedSizeForVersion(uint64_t); \
dyld_all_image_infos<Traits##lp_bits>::ExpectedSizeForVersion( \
decltype(dyld_all_image_infos<Traits##lp_bits>::version)); \
template bool dyld_all_image_infos<Traits##lp_bits>::ReadInto( \
ProcessReader*, \
mach_vm_address_t, \
dyld_all_image_infos<Traits##lp_bits>*); \
template size_t \
crashreporter_annotations_t<Traits##lp_bits>::ExpectedSizeForVersion( \
uint64_t); \
decltype(crashreporter_annotations_t<Traits##lp_bits>::version)); \
template bool crashreporter_annotations_t<Traits##lp_bits>::ReadInto( \
ProcessReader*, \
mach_vm_address_t, \

View File

@ -45,6 +45,7 @@ PROCESS_TYPE_STRUCT_END(dyld_uuid_info)
PROCESS_TYPE_STRUCT_BEGIN(dyld_all_image_infos)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, version)
PROCESS_TYPE_STRUCT_VERSIONED(dyld_all_image_infos, version)
// Version 1 (Mac OS X 10.4)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, infoArrayCount)