1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #ifndef SYZYGY_REFINERY_UNITTEST_UTIL_H_
16 : #define SYZYGY_REFINERY_UNITTEST_UTIL_H_
17 :
18 : #include <cstdint>
19 : #include <map>
20 : #include <string>
21 : #include <utility>
22 : #include <vector>
23 :
24 : #include "base/files/file_path.h"
25 : #include "base/files/scoped_temp_dir.h"
26 : #include "base/strings/string_piece.h"
27 : #include "gtest/gtest.h"
28 : #include "syzygy/refinery/core/address.h"
29 : #include "syzygy/refinery/process_state/process_state.h"
30 :
31 : namespace testing {
32 :
33 : // A MinidumpSpecification is used to describe and generate synthetic minidumps.
34 : // If the specification is serialized, the generated minidump is erased as the
35 : // specification is deleted.
36 : class MinidumpSpecification {
37 : public:
38 : // Forward.
39 : struct MemorySpecification;
40 : struct ThreadSpecification;
41 : struct ExceptionSpecification;
42 : struct ModuleSpecification;
43 :
44 : enum AllowMemoryOverlap {
45 : ALLOW_MEMORY_OVERLAP,
46 : };
47 :
48 : MinidumpSpecification();
49 : explicit MinidumpSpecification(AllowMemoryOverlap dummy);
50 :
51 : // Adds thread data to the specification. Note that the stack's memory must
52 : // be added independently to the specification. The adbsence of a memory
53 : // region spanning the stack's range leads to failure at serialization time.
54 : // @pre @p thread.thread_data.size() must be sizeof(MINIDUMP_THREAD).
55 : // @pre @p thread.context_data.size() must be sizeof(CONTEXT).
56 : // @param thread the specification of the thread data to addd.
57 : // @returns true on success, false otherwise.
58 : // TODO(manzagop): worth avoiding the copy? Here and below.
59 : bool AddThread(const ThreadSpecification& thread);
60 :
61 : // Adds a memory region to the specification.
62 : // @param addr the memory specification to add.
63 : // @returns true on success, false if the memory region is not valid or if it
64 : // overlaps with an existing memory region.
65 : bool AddMemoryRegion(const MemorySpecification& spec);
66 :
67 : // Adds a module to the specification.
68 : // @param module the specification of the module to add.
69 : // @returns true on success, false otherwise.
70 : bool AddModule(const ModuleSpecification& module);
71 :
72 : // Adds an exception to the specification.
73 : // @param module the specification of the exception to add.
74 : // @returns true on success, false otherwise.
75 : bool AddException(const ExceptionSpecification& exception);
76 :
77 : // Serializes the specification.
78 : // @param dir the directory to serialize to.
79 : // @param path the path to the minidump.
80 : // @returns true on success, false otherwise.
81 : bool Serialize(const base::ScopedTempDir& dir, base::FilePath* path) const;
82 :
83 : private:
84 : std::vector<ThreadSpecification> threads_; // Represents thread and context.
85 : std::vector<MemorySpecification> memory_regions_;
86 : std::vector<ModuleSpecification> modules_;
87 : std::vector<ExceptionSpecification> exceptions_;
88 :
89 : bool allow_memory_overlap_;
90 : std::map<refinery::Address, refinery::Size> region_sizes_;
91 :
92 : DISALLOW_COPY_AND_ASSIGN(MinidumpSpecification);
93 : };
94 :
95 : class SyntheticMinidumpTest : public testing::Test {
96 : protected:
97 E : void SetUp() override {
98 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
99 E : }
100 :
101 E : void Serialize(const MinidumpSpecification& spec) {
102 E : ASSERT_TRUE(spec.Serialize(temp_dir_, &dump_file_));
103 E : }
104 :
105 E : const base::FilePath& dump_file() const { return dump_file_; }
106 :
107 : private:
108 : base::ScopedTempDir temp_dir_;
109 : base::FilePath dump_file_;
110 : };
111 :
112 : struct MinidumpSpecification::MemorySpecification {
113 : MemorySpecification();
114 : MemorySpecification(refinery::Address addr, base::StringPiece data);
115 :
116 : refinery::Address address;
117 : std::string buffer;
118 : };
119 :
120 : struct MinidumpSpecification::ThreadSpecification {
121 : // Constructor that initializes the specification using provided parameters.
122 : // @param thread_id the id of the thread.
123 : // @param stack_address the address id of the thread's stack.
124 : // @param stack_size the size of the thread's stack.
125 : ThreadSpecification(size_t thread_id,
126 : refinery::Address stack_address,
127 : refinery::Size stack_size);
128 :
129 : void SetTebAddress(refinery::Address addr);
130 :
131 : // Sets @p spec to a memory specification that is suitable for backing with
132 : // the current specification's stack.
133 : // @param spec the memory specification to set.
134 : void FillStackMemorySpecification(
135 : MinidumpSpecification::MemorySpecification* spec) const;
136 :
137 : std::string thread_data; // represents a MINIDUMP_THREAD.
138 : std::string context_data; // represents a CONTEXT.
139 : };
140 :
141 : struct MinidumpSpecification::ExceptionSpecification {
142 : explicit ExceptionSpecification(uint32 thread_id);
143 :
144 : uint32 thread_id;
145 : uint32 exception_code;
146 : uint32 exception_flags;
147 : uint64 exception_record;
148 : uint64 exception_address;
149 : std::vector<uint64> exception_information;
150 :
151 : std::string context_data; // represents a CONTEXT.
152 : };
153 :
154 : struct MinidumpSpecification::ModuleSpecification {
155 : ModuleSpecification();
156 :
157 : refinery::Address addr;
158 : refinery::Size size;
159 : uint32 checksum;
160 : uint32 timestamp;
161 : std::string name;
162 : };
163 :
164 : // Allows grabbing a minidump of our own process.
165 : class ScopedMinidump {
166 : public:
167 : // Minidump with stacks, but no referenced data.
168 : static const uint32_t kMinidumpWithStacks;
169 : // Minidump with stacks and referenced data.
170 : static const uint32_t kMinidumpWithData;
171 :
172 : ScopedMinidump() = default;
173 :
174 : bool GenerateMinidump(uint32_t minidump_type);
175 :
176 : base::FilePath temp_dir() { return temp_dir_.path(); }
177 E : base::FilePath minidump_path() { return minidump_path_; }
178 :
179 : private:
180 : base::ScopedTempDir temp_dir_;
181 : base::FilePath minidump_path_;
182 :
183 : DISALLOW_COPY_AND_ASSIGN(ScopedMinidump);
184 E : };
185 :
186 : // Wraps a Windows heap for testing purposes.
187 : class ScopedHeap {
188 : public:
189 : ScopedHeap();
190 : ~ScopedHeap();
191 :
192 : bool Create();
193 :
194 : void* Allocate(size_t block_size);
195 : bool Free(void* block);
196 :
197 : bool IsLFHBlock(const void* ptr);
198 :
199 : private:
200 : HANDLE heap_;
201 :
202 : DISALLOW_COPY_AND_ASSIGN(ScopedHeap);
203 : };
204 :
205 : // Casts a pointer to an address.
206 : refinery::Address ToAddress(const void* ptr);
207 :
208 : // Tests for the presence of appverifier.
209 : bool IsAppVerifierActive();
210 :
211 : } // namespace testing
212 :
213 : #endif // SYZYGY_REFINERY_UNITTEST_UTIL_H_
|