Index: util/mac/process_types.cc |
diff --git a/util/mac/process_types.cc b/util/mac/process_types.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e7e858bf822756427eafd28eafbeff609275bf14 |
--- /dev/null |
+++ b/util/mac/process_types.cc |
@@ -0,0 +1,244 @@ |
+// 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/mac/process_types.h" |
+ |
+#include <string.h> |
+#include <uuid/uuid.h> |
+ |
+#include "base/memory/scoped_ptr.h" |
+#include "util/mac/process_types/internal.h" |
+#include "util/mach/task_memory.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 <typename DestinationType, typename SourceType> |
+inline void Assign(DestinationType* destination, const SourceType& source) { |
+ *destination = source; |
+} |
+ |
+template <> |
+inline void Assign<process_types::internal::Reserved64Only64, |
+ process_types::internal::Reserved64Only32>( |
+ process_types::internal::Reserved64Only64* destination, |
+ const process_types::internal::Reserved64Only32& source) { |
+ // Reserved64Only32 carries no data. |
+ *destination = 0; |
+} |
+ |
+typedef char CharArray16[16]; |
+template <> |
+inline void Assign<CharArray16, CharArray16>(CharArray16* destination, |
+ const CharArray16& source) { |
+ memcpy(destination, &source, sizeof(source)); |
+} |
+ |
+typedef uint64_t UInt64Array16[16]; |
+template <> |
+inline void Assign<UInt64Array16, UInt64Array16>(UInt64Array16* destination, |
+ const UInt64Array16& source) { |
+ memcpy(destination, &source, sizeof(source)); |
+} |
+ |
+typedef uint32_t UInt32Array16[16]; |
+template <> |
+inline void Assign<UInt64Array16, UInt32Array16>(UInt64Array16* destination, |
+ const UInt32Array16& source) { |
+ for (size_t index = 0; index < arraysize(source); ++index) { |
+ (*destination)[index] = source[index]; |
+ } |
+} |
+ |
+template <> |
+inline void Assign<uuid_t, uuid_t>(uuid_t* destination, const uuid_t& source) { |
+ // uuid_t is a typedef for unsigned char[16]. |
+ memcpy(destination, &source, sizeof(source)); |
+} |
+ |
+} // 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 { \ |
+ \ |
+ 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(); \ |
+ } \ |
+ } \ |
+ \ |
+ 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); \ |
+ } \ |
+ } \ |
+ \ |
+ 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_END(struct_name) \ |
+ } \ |
+ } /* namespace internal */ \ |
+ } /* namespace process_types */ \ |
+ } /* namespace crashpad */ |
+ |
+#include "util/mac/process_types/all.proctype" |
+ |
+#undef PROCESS_TYPE_STRUCT_BEGIN |
+#undef PROCESS_TYPE_STRUCT_MEMBER |
+#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 util/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 { \ |
+ \ |
+ template <typename Traits> \ |
+ bool struct_name<Traits>::ReadInto(ProcessReader* process_reader, \ |
+ mach_vm_address_t address, \ |
+ struct_name<Traits>* 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_END(struct_name) |
+ |
+#include "util/mac/process_types/all.proctype" |
+ |
+#undef PROCESS_TYPE_STRUCT_BEGIN |
+#undef PROCESS_TYPE_STRUCT_MEMBER |
+#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 { \ |
+ \ |
+ template <typename Traits> \ |
+ bool struct_name<Traits>::ReadArrayInto(ProcessReader* process_reader, \ |
+ mach_vm_address_t address, \ |
+ size_t count, \ |
+ struct_name<Traits>* specific) { \ |
+ return process_reader->Memory()->Read( \ |
+ address, sizeof(struct_name<Traits> [count]), specific); \ |
+ } \ |
+ } /* namespace internal */ \ |
+ \ |
+ bool struct_name::ReadArrayInto(ProcessReader* process_reader, \ |
+ mach_vm_address_t address, \ |
+ size_t count, \ |
+ struct_name* generic) { \ |
+ if (!process_reader->Is64Bit()) { \ |
+ return ReadArrayIntoInternal< \ |
+ internal::struct_name<internal::Traits32> >( \ |
+ process_reader, address, count, generic); \ |
+ } else { \ |
+ return ReadArrayIntoInternal< \ |
+ internal::struct_name<internal::Traits64> >( \ |
+ process_reader, address, count, generic); \ |
+ } \ |
+ return true; \ |
+ } \ |
+ \ |
+ template <typename T> \ |
+ bool struct_name::ReadArrayIntoInternal(ProcessReader* process_reader, \ |
+ mach_vm_address_t address, \ |
+ size_t count, \ |
+ struct_name* generic) { \ |
+ scoped_ptr<T[]> 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_END(struct_name) |
+ |
+#include "util/mac/process_types/all.proctype" |
+ |
+#undef PROCESS_TYPE_STRUCT_BEGIN |
+#undef PROCESS_TYPE_STRUCT_MEMBER |
+#undef PROCESS_TYPE_STRUCT_END |
+#undef PROCESS_TYPE_STRUCT_IMPLEMENT_ARRAY |