1 : // Copyright 2013 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 : #include "syzygy/agent/asan/stack_capture.h"
16 :
17 : #include "base/logging.h"
18 : #include "base/process_util.h"
19 :
20 : // http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
21 : extern "C" IMAGE_DOS_HEADER __ImageBase;
22 :
23 : namespace agent {
24 : namespace asan {
25 :
26 E : uint32 ComputeStackTraceHash(void** stack_trace, uint8 stack_depth) {
27 E : uint32 hash_value = 0;
28 E : for (uint8 i = 0; i < stack_depth; ++i) {
29 E : hash_value += reinterpret_cast<uint32>(stack_trace[i]);
30 E : }
31 E : return hash_value;
32 E : }
33 :
34 : // The biggest gain observed on stack cache compression is when we skip the 5
35 : // bottom frames of the stack traces. To measure this gain we've run an
36 : // instrumented version of base_unittests and observed the cache compression.
37 : // With a value between 0 and 4 the compression ratio was around 28.9%, and with
38 : // a value of 5 it was 92.19%.
39 : // NOTE: This is mostly for Chrome's unittests, the side effect is that the
40 : // bottom frames of the allocation and free stack traces of any instrumented
41 : // image will be elided, but from what we've seen they're rarely precise and
42 : // useful (they refer to the entry point of the image).
43 : size_t StackCapture::bottom_frames_to_skip_ = 5;
44 :
45 E : size_t StackCapture::GetSize(size_t max_num_frames) {
46 E : DCHECK_LT(0u, max_num_frames);
47 E : max_num_frames = std::min(max_num_frames, kMaxNumFrames);
48 E : return offsetof(StackCapture, frames_) + max_num_frames * sizeof(void*);
49 E : }
50 :
51 : void StackCapture::InitFromBuffer(StackId stack_id,
52 : const void* const* frames,
53 E : size_t num_frames) {
54 E : DCHECK(frames != NULL);
55 E : DCHECK_LT(0U, num_frames);
56 E : stack_id_ = stack_id;
57 E : num_frames_ = std::min<uint8>(num_frames, max_num_frames_);
58 E : ::memcpy(frames_, frames, num_frames_ * sizeof(void*));
59 E : }
60 :
61 E : StackCapture::StackId StackCapture::ComputeRelativeStackId() {
62 : // We want to ignore the frames relative to our module to be able to get the
63 : // same trace id even if we update our runtime.
64 E : HANDLE asan_handle = reinterpret_cast<HANDLE>(&__ImageBase);
65 E : DCHECK(asan_handle != NULL);
66 :
67 E : StackId stack_id = 0;
68 E : for (size_t i = 0; i < num_frames_; ++i) {
69 E : HMODULE module = base::GetModuleFromAddress(frames_[i]);
70 E : if (module == NULL || module == asan_handle)
71 E : continue;
72 : stack_id += reinterpret_cast<size_t>(frames_[i]) -
73 E : reinterpret_cast<size_t>(module);
74 E : }
75 :
76 E : return stack_id;
77 E : }
78 :
79 : size_t StackCapture::HashCompare::operator()(
80 E : const StackCapture* stack_capture) const {
81 E : DCHECK(stack_capture != NULL);
82 : // We're assuming that the StackId and size_t have the same size, so let's
83 : // make sure that's the case.
84 : COMPILE_ASSERT(sizeof(StackId) == sizeof(size_t),
85 : stack_id_and_size_t_not_same_size);
86 E : return stack_capture->stack_id_;
87 E : }
88 :
89 : bool StackCapture::HashCompare::operator()(
90 : const StackCapture* stack_capture1,
91 E : const StackCapture* stack_capture2) const {
92 E : DCHECK(stack_capture1 != NULL);
93 E : DCHECK(stack_capture2 != NULL);
94 E : return stack_capture1->stack_id_ < stack_capture2->stack_id_;
95 E : }
96 :
97 : } // namespace asan
98 : } // namespace agent
|