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 : #include "syzygy/agent/common/process_utils.h"
16 :
17 : #include <algorithm>
18 :
19 : #include "base/environment.h"
20 : #include "base/file_util.h"
21 : #include "base/files/file_enumerator.h"
22 : #include "base/files/scoped_temp_dir.h"
23 : #include "base/strings/utf_string_conversions.h"
24 : #include "gtest/gtest.h"
25 : #include "syzygy/trace/client/rpc_session.h"
26 : #include "syzygy/trace/common/unittest_util.h"
27 : #include "syzygy/trace/parse/unittest_util.h"
28 :
29 : namespace agent {
30 : namespace common {
31 :
32 : namespace {
33 :
34 : using testing::_;
35 : using testing::StrictMockParseEventHandler;
36 : using trace::parser::Parser;
37 :
38 E : MATCHER_P(ModuleAtAddress, module, "") {
39 E : return arg->module_base_addr == module;
40 E : }
41 :
42 : // TODO(chrisha): Create agent_test_utils, and centralize the basic
43 : // functionality of this fixture. All agents can then use that.
44 : // Don't forget the 'ModuleAtAddress' above as well.
45 : class ProcessUtilsTest : public testing::Test {
46 : public:
47 E : virtual void SetUp() OVERRIDE {
48 E : testing::Test::SetUp();
49 :
50 : // Call trace files will be stuffed here.
51 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
52 :
53 E : service_.SetEnvironment();
54 E : }
55 :
56 E : virtual void TearDown() OVERRIDE {
57 E : service_.Stop();
58 E : }
59 :
60 E : void StartService() {
61 E : service_.Start(temp_dir_.path());
62 E : }
63 :
64 E : void StopService() {
65 E : service_.Stop();
66 E : }
67 :
68 E : void ReplayLogs(size_t files_expected) {
69 : // Stop the service if it's running.
70 E : ASSERT_NO_FATAL_FAILURE(StopService());
71 :
72 E : Parser parser;
73 E : ASSERT_TRUE(parser.Init(&handler_));
74 :
75 : // Queue up the trace file(s) we engendered.
76 : base::FileEnumerator enumerator(temp_dir_.path(),
77 : false,
78 E : base::FileEnumerator::FILES);
79 E : size_t num_files = 0;
80 E : while (true) {
81 E : base::FilePath trace_file = enumerator.Next();
82 E : if (trace_file.empty())
83 E : break;
84 E : ASSERT_TRUE(parser.OpenTraceFile(trace_file));
85 E : ++num_files;
86 E : }
87 :
88 E : EXPECT_EQ(files_expected, num_files);
89 :
90 E : if (num_files > 0)
91 E : ASSERT_TRUE(parser.Consume());
92 E : }
93 :
94 : protected:
95 : // The directory where trace file output will be written.
96 : base::ScopedTempDir temp_dir_;
97 :
98 : // The handler to which the trace file parser will delegate events.
99 : StrictMockParseEventHandler handler_;
100 :
101 : // Our call trace service process instance.
102 : testing::CallTraceService service_;
103 : };
104 :
105 : } // namespace
106 :
107 E : TEST_F(ProcessUtilsTest, GetProcessModules) {
108 E : ModuleVector modules;
109 :
110 E : GetProcessModules(&modules);
111 :
112 : // Make sure our own module is in the list.
113 E : HMODULE exe_module = ::GetModuleHandle(NULL);
114 : EXPECT_TRUE(
115 E : std::find(modules.begin(), modules.end(), exe_module) != modules.end());
116 :
117 : // We have some imports, so there should be
118 : // more than just our own module here.
119 E : EXPECT_LT(1U, modules.size());
120 E : }
121 :
122 E : TEST_F(ProcessUtilsTest, LogModule) {
123 E : ASSERT_NO_FATAL_FAILURE(StartService());
124 :
125 : // Initialize the session.
126 E : trace::client::RpcSession session;
127 E : trace::client::TraceFileSegment segment;
128 E : std::string id = trace::client::GetInstanceIdForThisModule();
129 E : session.set_instance_id(base::UTF8ToWide(id));
130 E : session.CreateSession(&segment);
131 :
132 E : HMODULE self = ::GetModuleHandle(NULL);
133 E : DWORD process_id = ::GetCurrentProcessId();
134 E : DWORD thread_id = ::GetCurrentThreadId();
135 :
136 E : ASSERT_TRUE(LogModule(self, &session, &segment));
137 :
138 : // Logging an unloaded or invalid module should fail.
139 :
140 E : size_t kAllocSize = 4096;
141 : // Reserve an unmapped range of memory.
142 : void* unmapped =
143 E : ::VirtualAlloc(NULL, kAllocSize, MEM_RESERVE, PAGE_READWRITE);
144 E : ASSERT_NE(static_cast<void*>(NULL), unmapped);
145 :
146 : // Make sure logging the address as a module fails, logs nothing, but
147 : // doesn't crash. This simulates logging an unloaded module.
148 E : ASSERT_FALSE(LogModule(static_cast<HMODULE>(unmapped), &session, &segment));
149 :
150 : // Now allocate the first page, and make sure we don't log it absent the
151 : // magic numbers in a valid module. This simulates logging an unloaded
152 : // module, whose address space has been reused for data.
153 : ASSERT_NE(static_cast<void*>(NULL),
154 E : ::VirtualAlloc(unmapped, kAllocSize, MEM_COMMIT, PAGE_READWRITE));
155 E : ASSERT_FALSE(LogModule(static_cast<HMODULE>(unmapped), &session, &segment));
156 :
157 : // Free our alloc.
158 E : EXPECT_TRUE(::VirtualFree(unmapped, 0, MEM_RELEASE));
159 :
160 E : ASSERT_NO_FATAL_FAILURE(StopService());
161 :
162 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
163 : EXPECT_CALL(handler_, OnProcessAttach(_,
164 : process_id,
165 : thread_id,
166 E : ModuleAtAddress(self)));
167 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
168 :
169 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(1));
170 E : }
171 :
172 : } // namespace common
173 : } // namespace agent
|