// 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 "snapshot/mac/process_types.h" #include #include #include #include #include "base/cxx17_backports.h" #include "snapshot/mac/process_types/internal.h" #include "util/process/process_memory_mac.h" namespace crashpad { namespace { // Assign() is used by each flavor's ReadInto implementation to copy data from a // specific struct to a generic struct. For fundamental types, the assignment // operator suffices. For other types such as arrays, an explicit Assign // specialization is needed, typically performing a copy. template inline void Assign(DestinationType* destination, const SourceType& source) { *destination = source; } template inline void Assign(Type* destination, const Type& source) { memcpy(destination, &source, sizeof(source)); } template <> inline void Assign( process_types::internal::Reserved32_32Only64* destination, const process_types::internal::Reserved32_32Only32& source) { // Reserved32_32Only32 carries no data and has no storage in the 64-bit // structure. } template <> inline void Assign( process_types::internal::Reserved32_64Only64* destination, const process_types::internal::Reserved32_64Only32& source) { // Reserved32_64Only32 carries no data. *destination = 0; } template <> inline void Assign( process_types::internal::Reserved64_64Only64* destination, const process_types::internal::Reserved64_64Only32& source) { // Reserved64_64Only32 carries no data. *destination = 0; } using UInt32Array4 = uint32_t[4]; using UInt64Array4 = uint64_t[4]; template <> inline void Assign(UInt64Array4* destination, const UInt32Array4& source) { for (size_t index = 0; index < base::size(source); ++index) { (*destination)[index] = source[index]; } } } // namespace } // namespace crashpad // Implement the generic crashpad::process_types::struct_name ReadInto(), which // delegates to the templatized ReadIntoInternal(), which reads the specific // struct type from the remote process and genericizes it. Also implement // crashpad::process_types::internal::struct_name<> GenericizeInto(), which // 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(ProcessReaderMac* process_reader) { \ if (!process_reader->Is64Bit()) { \ return internal::struct_name::Size(); \ } else { \ return internal::struct_name::Size(); \ } \ } \ \ /* static */ \ bool struct_name::ReadInto(ProcessReaderMac* process_reader, \ mach_vm_address_t address, \ struct_name* generic) { \ if (!process_reader->Is64Bit()) { \ return ReadIntoInternal>( \ process_reader, address, generic); \ } else { \ return ReadIntoInternal>( \ process_reader, address, generic); \ } \ } \ \ /* static */ \ template \ bool struct_name::ReadIntoInternal(ProcessReaderMac* 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 \ void struct_name::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_SIZED(struct_name, size_field) #define PROCESS_TYPE_STRUCT_END(struct_name) \ } \ } /* namespace internal */ \ } /* namespace process_types */ \ } /* namespace crashpad */ #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_SIZED #undef PROCESS_TYPE_STRUCT_END #undef PROCESS_TYPE_STRUCT_IMPLEMENT // Implement the specific crashpad::process_types::internal::struct_name<> // ReadInto(). The default implementation simply reads the struct from the // remote process. This is separated from other method implementations because // some types may wish to provide custom readers. This can be done by guarding // such types’ proctype definitions against this macro and providing custom // implementations in snapshot/mac/process_types/custom.cc. #define PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO 1 #define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \ namespace crashpad { \ namespace process_types { \ namespace internal { \ \ /* static */ \ template \ bool struct_name::ReadInto(ProcessReaderMac* process_reader, \ mach_vm_address_t address, \ struct_name* specific) { \ return process_reader->Memory()->Read( \ address, sizeof(*specific), specific); \ } \ } /* namespace internal */ \ } /* namespace process_types */ \ } /* namespace crashpad */ #define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) #define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field) #define PROCESS_TYPE_STRUCT_SIZED(struct_name, size_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_SIZED #undef PROCESS_TYPE_STRUCT_END #undef PROCESS_TYPE_STRUCT_IMPLEMENT_INTERNAL_READ_INTO // Implement the array operations. These are separated from other method // implementations because some types are variable-length and are never stored // as direct-access arrays. It would be incorrect to provide reader // implementations for such types. Types that wish to suppress array operations // can do so by guarding their proctype definitions against this macro. #define PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY 1 #define PROCESS_TYPE_STRUCT_BEGIN(struct_name) \ namespace crashpad { \ namespace process_types { \ namespace internal { \ \ /* static */ \ template \ bool struct_name::ReadArrayInto(ProcessReaderMac* process_reader, \ mach_vm_address_t address, \ size_t count, \ struct_name* specific) { \ return process_reader->Memory()->Read( \ address, count * sizeof(struct_name), specific); \ } \ \ } /* namespace internal */ \ \ /* static */ \ bool struct_name::ReadArrayInto(ProcessReaderMac* process_reader, \ mach_vm_address_t address, \ size_t count, \ struct_name* generic) { \ if (!process_reader->Is64Bit()) { \ return ReadArrayIntoInternal>( \ process_reader, address, count, generic); \ } else { \ return ReadArrayIntoInternal>( \ process_reader, address, count, generic); \ } \ return true; \ } \ \ /* static */ \ template \ bool struct_name::ReadArrayIntoInternal(ProcessReaderMac* process_reader, \ mach_vm_address_t address, \ size_t count, \ struct_name* generic) { \ std::unique_ptr specific(new T[count]); \ if (!T::ReadArrayInto(process_reader, address, count, &specific[0])) { \ return false; \ } \ for (size_t index = 0; index < count; ++index) { \ specific[index].GenericizeInto(&generic[index], &generic[index].size_); \ } \ return true; \ } \ } /* namespace process_types */ \ } /* namespace crashpad */ #define PROCESS_TYPE_STRUCT_MEMBER(member_type, member_name, ...) #define PROCESS_TYPE_STRUCT_VERSIONED(struct_name, version_field) #define PROCESS_TYPE_STRUCT_SIZED(struct_name, size_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_SIZED #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( \ ProcessReaderMac* 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_SIZED(struct_name, size_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_SIZED #undef PROCESS_TYPE_STRUCT_END #undef PROCESS_TYPE_STRUCT_IMPLEMENT_VERSIONED // Implement the generic crashpad::process_types::struct_name MinimumSize() and // its templatized equivalent. The generic version delegates to the templatized // one, which returns the minimum size of a sized structure. This can be used to // ensure that enough of a sized structure is available to interpret its size // field. This is only implemented for structures that use // PROCESS_TYPE_STRUCT_SIZED(). #define PROCESS_TYPE_STRUCT_IMPLEMENT_SIZED 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) #define PROCESS_TYPE_STRUCT_SIZED(struct_name, size_field) \ namespace crashpad { \ namespace process_types { \ \ namespace internal { \ \ /* static */ \ template \ size_t struct_name::MinimumSize() { \ return offsetof(struct_name, size_field) + \ sizeof(struct_name::size_field); \ } \ \ /* Explicit instantiations of the above. */ \ template size_t struct_name::MinimumSize(); \ template size_t struct_name::MinimumSize(); \ \ } /* namespace internal */ \ \ /* static */ \ size_t struct_name::MinimumSize(ProcessReaderMac* process_reader) { \ if (!process_reader->Is64Bit()) { \ return internal::struct_name::MinimumSize(); \ } else { \ return internal::struct_name::MinimumSize(); \ } \ } \ \ } /* 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_SIZED #undef PROCESS_TYPE_STRUCT_END #undef PROCESS_TYPE_STRUCT_IMPLEMENT_SIZED