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 m : 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 m : class MinidumpSpecification {
37 m : public:
38 : // Forward.
39 m : struct MemorySpecification;
40 m : struct ThreadSpecification;
41 m : struct ExceptionSpecification;
42 m : struct ModuleSpecification;
43 :
44 m : enum AllowMemoryOverlap {
45 m : ALLOW_MEMORY_OVERLAP,
46 m : };
47 :
48 m : MinidumpSpecification();
49 m : 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 m : 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 m : 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 m : 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 m : 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 m : bool Serialize(const base::ScopedTempDir& dir, base::FilePath* path) const;
82 :
83 m : private:
84 m : std::vector<ThreadSpecification> threads_; // Represents thread and context.
85 m : std::vector<MemorySpecification> memory_regions_;
86 m : std::vector<ModuleSpecification> modules_;
87 m : std::vector<ExceptionSpecification> exceptions_;
88 :
89 m : bool allow_memory_overlap_;
90 m : std::map<refinery::Address, refinery::Size> region_sizes_;
91 :
92 m : DISALLOW_COPY_AND_ASSIGN(MinidumpSpecification);
93 m : };
94 :
95 m : class SyntheticMinidumpTest : public testing::Test {
96 m : protected:
97 m : void SetUp() override {
98 m : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
99 m : }
100 :
101 m : void Serialize(const MinidumpSpecification& spec) {
102 m : ASSERT_TRUE(spec.Serialize(temp_dir_, &dump_file_));
103 m : }
104 :
105 m : const base::FilePath& dump_file() const { return dump_file_; }
106 :
107 m : private:
108 m : base::ScopedTempDir temp_dir_;
109 m : base::FilePath dump_file_;
110 m : };
111 :
112 m : struct MinidumpSpecification::MemorySpecification {
113 m : MemorySpecification();
114 m : MemorySpecification(refinery::Address addr, base::StringPiece data);
115 :
116 m : refinery::Address address;
117 m : std::string buffer;
118 m : };
119 :
120 m : 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 m : ThreadSpecification(size_t thread_id,
126 m : refinery::Address stack_address,
127 m : refinery::Size stack_size);
128 :
129 m : 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 m : void FillStackMemorySpecification(
135 m : MinidumpSpecification::MemorySpecification* spec) const;
136 :
137 m : std::string thread_data; // represents a MINIDUMP_THREAD.
138 m : std::string context_data; // represents a CONTEXT.
139 m : };
140 :
141 m : struct MinidumpSpecification::ExceptionSpecification {
142 m : explicit ExceptionSpecification(uint32_t thread_id);
143 :
144 m : uint32_t thread_id;
145 m : uint32_t exception_code;
146 m : uint32_t exception_flags;
147 m : uint64_t exception_record;
148 m : uint64_t exception_address;
149 m : std::vector<uint64_t> exception_information;
150 :
151 m : std::string context_data; // represents a CONTEXT.
152 m : };
153 :
154 m : struct MinidumpSpecification::ModuleSpecification {
155 m : ModuleSpecification();
156 :
157 m : refinery::Address addr;
158 m : refinery::Size size;
159 m : uint32_t checksum;
160 m : uint32_t timestamp;
161 m : std::string name;
162 m : };
163 :
164 : // Allows grabbing a minidump of our own process.
165 m : class ScopedMinidump {
166 m : public:
167 : // Minidump with stacks, but no referenced data.
168 m : static const uint32_t kMinidumpWithStacks;
169 : // Minidump with stacks and referenced data.
170 m : static const uint32_t kMinidumpWithData;
171 :
172 m : ScopedMinidump() = default;
173 :
174 m : bool GenerateMinidump(uint32_t minidump_type);
175 :
176 m : base::FilePath temp_dir() { return temp_dir_.path(); }
177 m : base::FilePath minidump_path() { return minidump_path_; }
178 :
179 m : private:
180 m : base::ScopedTempDir temp_dir_;
181 m : base::FilePath minidump_path_;
182 :
183 m : DISALLOW_COPY_AND_ASSIGN(ScopedMinidump);
184 m : };
185 :
186 : // Wraps a Windows heap for testing purposes.
187 m : class ScopedHeap {
188 m : public:
189 m : ScopedHeap();
190 m : ~ScopedHeap();
191 :
192 m : bool Create();
193 :
194 m : void* Allocate(size_t block_size);
195 m : bool Free(void* block);
196 :
197 m : bool IsLFHBlock(const void* ptr);
198 :
199 m : private:
200 m : HANDLE heap_;
201 :
202 m : DISALLOW_COPY_AND_ASSIGN(ScopedHeap);
203 m : };
204 :
205 : // Casts a pointer to an address.
206 m : refinery::Address ToAddress(const void* ptr);
207 :
208 : // Tests for the presence of appverifier.
209 m : bool IsAppVerifierActive();
210 :
211 m : } // namespace testing
212 :
213 : #endif // SYZYGY_REFINERY_UNITTEST_UTIL_H_
|