1 : // Copyright 2012 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 : // A class that take care of initializing asan run-time library.
16 :
17 : #ifndef SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
18 : #define SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
19 :
20 : #include <set>
21 : #include <string>
22 :
23 : #include "base/callback.h"
24 : #include "base/logging.h"
25 : #include "base/memory/scoped_ptr.h"
26 : #include "base/synchronization/lock.h"
27 : #include "syzygy/agent/asan/asan_heap.h"
28 : #include "syzygy/agent/asan/stack_capture.h"
29 : #include "syzygy/agent/common/dlist.h"
30 :
31 : namespace agent {
32 : namespace asan {
33 :
34 : class AsanLogger;
35 :
36 : // Store the information about a bad memory access.
37 : struct AsanErrorInfo {
38 : // The address where the bad access happened.
39 : void* location;
40 : // The context prior to the crash.
41 : CONTEXT context;
42 : // The allocation stack trace.
43 : void* alloc_stack[agent::asan::StackCapture::kMaxNumFrames];
44 : // The size of the allocation stack trace.
45 : uint8 alloc_stack_size;
46 : // The ID of the allocation thread.
47 : DWORD alloc_tid;
48 : // The free stack trace.
49 : void* free_stack[agent::asan::StackCapture::kMaxNumFrames];
50 : // The size of the free stack trace.
51 : uint8 free_stack_size;
52 : // The ID of the free thread.
53 : DWORD free_tid;
54 : // The ID of the crash stack, this is needed to be able to blacklist some
55 : // known bugs.
56 : StackCapture::StackId crash_stack_id;
57 : // The error type.
58 : HeapProxy::BadAccessKind error_type;
59 : // The access mode.
60 : HeapProxy::AccessMode access_mode;
61 : // The access size.
62 : size_t access_size;
63 : // The information about the shadow memory for this address, this would be
64 : // something like: "0x12345678 is located 8 bytes inside of 10-bytes region
65 : // [0x12345670,0x1234567A)."
66 : char shadow_info[128];
67 : // A textual description of the shadow memory around |location|.
68 : char shadow_memory[512];
69 : // The time since the memory block containing this address has been freed.
70 : // This would be equal to zero if the block is still allocated.
71 : uint64 microseconds_since_free;
72 : };
73 :
74 : // An Asan Runtime manager.
75 : // This class takes care of initializing the different modules (stack cache,
76 : // logger...) and provide the functions to report an error.
77 : // Basic usage:
78 : // AsanRuntime* asan_runtime = new AsanRuntime();
79 : // std::wstring asan_flags_str;
80 : // AsanRuntime::GetAsanFlagsEnvVar(&asan_flags_str);
81 : // asan_runtime->SetUp(asan_flags_str); // Initialize the modules.
82 : // ...
83 : // AsanErrorInfo bad_access_info = {};
84 : // ::RtlCaptureContext(&bad_access_info.context);
85 : // StackCapture stack;
86 : // stack.InitFromStack();
87 : // stack.set_stack_id(stack.ComputeRelativeStackId());
88 : // bad_access_info.crash_stack_id = stack.stack_id();
89 : // asan_runtime->OnError(&bad_access_info);
90 : // asan_runtime->TearDown(); // Release the modules.
91 : // delete asan_runtime;
92 : class AsanRuntime {
93 : public:
94 : typedef std::set<StackCapture::StackId> StackIdSet;
95 :
96 : // The type of callback used by the OnError function.
97 : typedef base::Callback<void(AsanErrorInfo*)> AsanOnErrorCallBack;
98 :
99 : AsanRuntime();
100 : ~AsanRuntime();
101 :
102 : // @name Accessors.
103 : // @{
104 : AsanLogger* logger() {
105 : DCHECK(logger_.get() != NULL);
106 : return logger_.get();
107 : }
108 E : StackCaptureCache* stack_cache() {
109 E : DCHECK(stack_cache_.get() != NULL);
110 E : return stack_cache_.get();
111 E : }
112 E : static const wchar_t* SyzyAsanDll() {
113 E : return kSyzyAsanDll;
114 E : }
115 : // @}
116 :
117 : // Initialize asan runtime library.
118 : // @param flags_command_line The parameters string.
119 : void SetUp(const std::wstring& flags_command_line);
120 :
121 : // Release asan runtime library.
122 : void TearDown();
123 :
124 : // The error handler.
125 : // @param error_info The information about this error.
126 : void OnError(AsanErrorInfo* error_info);
127 :
128 : // Set the callback called on error.
129 : // TODO(sebmarchand): Move the signature of this callback to an header file
130 : // so it'll be easier to update it.
131 : void SetErrorCallBack(const AsanOnErrorCallBack& callback);
132 :
133 : // Try to read the Asan environment variable.
134 : // @param env_var_wstr The wstring where to store the environment variable.
135 : // returns true on success, false otherwise.
136 : static bool GetAsanFlagsEnvVar(std::wstring* env_var_wstr);
137 :
138 : // Add an heap proxy to the heap proxies list.
139 : void AddHeap(HeapProxy* heap);
140 :
141 : // Remove an heap proxy from the heap proxies list.
142 : void RemoveHeap(HeapProxy* heap);
143 :
144 : // Returns true if we should ignore the given @p stack_id, false
145 : // otherwise.
146 E : bool ShouldIgnoreError(size_t stack_id) const {
147 : // TODO(sebmarchand): Keep a list of the stack ids that have already been
148 : // reported so we can avoid reporting the same error multiple times.
149 : return flags_.ignored_stack_ids.find(stack_id) !=
150 E : flags_.ignored_stack_ids.end();
151 E : }
152 :
153 : // Get information about a bad access.
154 : // @param bad_access_info Will receive the information about this access.
155 : void GetBadAccessInformation(AsanErrorInfo* error_info);
156 :
157 : // The name of the environment variable holding the experiment opt-in coin
158 : // toss value.
159 : static const char kSyzygyAsanCoinTossEnvVar[];
160 :
161 : // The name of the environment variable containing the command-line.
162 : static const char kSyzygyAsanOptionsEnvVar[];
163 :
164 : protected:
165 : // A structure to track the values of the flags.
166 : struct AsanFlags {
167 : AsanFlags()
168 : : quarantine_size(0U),
169 : reporting_period(0U),
170 : bottom_frames_to_skip(0U),
171 : max_num_frames(0U),
172 : trailer_padding_size(0U),
173 : exit_on_failure(false),
174 : minidump_on_failure(false),
175 : log_as_text(true),
176 : opted_in(false),
177 E : coin_toss(0) {
178 E : }
179 :
180 : // The default size of the quarantine of the HeapProxy, in bytes.
181 : size_t quarantine_size;
182 :
183 : // The number of allocations between reports of the stack trace cache
184 : // compression ratio.
185 : size_t reporting_period;
186 :
187 : // The number of bottom frames to skip on a stack trace.
188 : size_t bottom_frames_to_skip;
189 :
190 : // The max number of frames for a stack trace.
191 : size_t max_num_frames;
192 :
193 : // The size of the padding added to every memory block trailer.
194 : size_t trailer_padding_size;
195 :
196 : // The stack ids we ignore.
197 : StackIdSet ignored_stack_ids;
198 :
199 : // If true, we should generate a minidump whenever an error is detected.
200 : // Defaults to false.
201 : bool minidump_on_failure;
202 :
203 : // If we should stop the logger (and the running program) after reporting
204 : // an error. Defaults to false.
205 : bool exit_on_failure;
206 :
207 : // If true, we should generate a textual log describing any errors.
208 : // Defaults to true;
209 : bool log_as_text;
210 :
211 : // Experiment configuration.
212 : bool opted_in;
213 : uint64 coin_toss;
214 : };
215 :
216 : // @name Flag strings.
217 : // @{
218 : static const char kBottomFramesToSkip[];
219 : static const char kCompressionReportingPeriod[];
220 : static const char kExitOnFailure[];
221 : static const char kIgnoredStackIds[];
222 : static const char kMaxNumberOfFrames[];
223 : static const char kMiniDumpOnFailure[];
224 : static const char kNoLogAsText[];
225 : static const char kQuarantineSize[];
226 : static const wchar_t kSyzyAsanDll[];
227 : static const char kTrailerPaddingSize[];
228 : // @}
229 :
230 : // @name Accessors.
231 : // @{
232 E : const AsanFlags* const flags() { return &flags_; }
233 : // @}
234 :
235 : // @name Mutators.
236 : // @{
237 : void set_flags(const AsanFlags* flags);
238 : // @}
239 :
240 : // Propagate the values of the flags to the target modules.
241 : void PropagateFlagsValues() const;
242 :
243 : private:
244 : // Set up the logger.
245 : void SetUpLogger();
246 :
247 : // Tear down the logger.
248 : void TearDownLogger();
249 :
250 : // Set up the stack cache.
251 : void SetUpStackCache();
252 :
253 : // Tear down the stack cache.
254 : void TearDownStackCache();
255 :
256 : // Parse and set the flags from the wide string @p str.
257 : bool ParseFlagsFromString(std::wstring str);
258 :
259 : // The shared logger instance that will be used by all heap proxies.
260 : scoped_ptr<AsanLogger> logger_;
261 :
262 : // The shared stack cache instance that will be used by all heap proxies.
263 : scoped_ptr<StackCaptureCache> stack_cache_;
264 :
265 : // The asan error callback functor.
266 : AsanOnErrorCallBack asan_error_callback_;
267 :
268 : // The values of the flags.
269 : AsanFlags flags_;
270 :
271 : // The heap proxies list lock.
272 : base::Lock heap_proxy_dlist_lock_;
273 :
274 : // The heap proxies list.
275 : LIST_ENTRY heap_proxy_dlist_; // Under heap_proxy_dlist_lock.
276 :
277 : DISALLOW_COPY_AND_ASSIGN(AsanRuntime);
278 : };
279 :
280 : } // namespace asan
281 : } // namespace agent
282 :
283 : #endif // SYZYGY_AGENT_ASAN_ASAN_RUNTIME_H_
|