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 number of bottom frames to skip per stack trace.
35 : size_t StackCapture::bottom_frames_to_skip_ = kDefaultBottomFramesToSkip_;
36 :
37 E : size_t StackCapture::GetSize(size_t max_num_frames) {
38 E : DCHECK_LT(0u, max_num_frames);
39 E : max_num_frames = std::min(max_num_frames, kMaxNumFrames);
40 E : return offsetof(StackCapture, frames_) + max_num_frames * sizeof(void*);
41 E : }
42 :
43 i : size_t StackCapture::GetMaxNumFrames(size_t bytes) {
44 i : if (bytes < offsetof(StackCapture, frames_))
45 i : return 0;
46 i : bytes -= offsetof(StackCapture, frames_);
47 i : bytes /= sizeof(void*);
48 i : return bytes;
49 i : }
50 :
51 E : void StackCapture::AddRef() {
52 E : if (RefCountIsSaturated())
53 i : return;
54 E : DCHECK_GT(kMaxRefCount, ref_count_);
55 E : ++ref_count_;
56 E : }
57 :
58 E : void StackCapture::RemoveRef() {
59 E : DCHECK_LT(0u, ref_count_);
60 E : if (RefCountIsSaturated())
61 E : return;
62 E : --ref_count_;
63 E : }
64 :
65 E : void StackCapture::Init() {
66 E : bottom_frames_to_skip_ = kDefaultBottomFramesToSkip_;
67 E : }
68 :
69 : void StackCapture::InitFromBuffer(StackId stack_id,
70 : const void* const* frames,
71 E : size_t num_frames) {
72 E : DCHECK(frames != NULL);
73 E : DCHECK_LT(0U, num_frames);
74 E : stack_id_ = stack_id;
75 E : num_frames_ = std::min<uint8>(num_frames, max_num_frames_);
76 E : ::memcpy(frames_, frames, num_frames_ * sizeof(void*));
77 E : }
78 :
79 E : StackCapture::StackId StackCapture::ComputeRelativeStackId() {
80 : // We want to ignore the frames relative to our module to be able to get the
81 : // same trace id even if we update our runtime.
82 E : HANDLE asan_handle = reinterpret_cast<HANDLE>(&__ImageBase);
83 E : DCHECK(asan_handle != NULL);
84 :
85 E : StackId stack_id = 0;
86 E : for (size_t i = 0; i < num_frames_; ++i) {
87 E : HMODULE module = base::GetModuleFromAddress(frames_[i]);
88 E : if (module == NULL || module == asan_handle)
89 E : continue;
90 : stack_id += reinterpret_cast<size_t>(frames_[i]) -
91 E : reinterpret_cast<size_t>(module);
92 E : }
93 :
94 E : return stack_id;
95 E : }
96 :
97 : size_t StackCapture::HashCompare::operator()(
98 E : const StackCapture* stack_capture) const {
99 E : DCHECK(stack_capture != NULL);
100 : // We're assuming that the StackId and size_t have the same size, so let's
101 : // make sure that's the case.
102 : COMPILE_ASSERT(sizeof(StackId) == sizeof(size_t),
103 : stack_id_and_size_t_not_same_size);
104 E : return stack_capture->stack_id_;
105 E : }
106 :
107 : bool StackCapture::HashCompare::operator()(
108 : const StackCapture* stack_capture1,
109 E : const StackCapture* stack_capture2) const {
110 E : DCHECK(stack_capture1 != NULL);
111 E : DCHECK(stack_capture2 != NULL);
112 E : return stack_capture1->stack_id_ < stack_capture2->stack_id_;
113 E : }
114 :
115 : } // namespace asan
116 : } // namespace agent
|