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/files/file_enumerator.h"
21 : #include "base/files/file_util.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 { service_.Stop(); }
57 :
58 E : void StartService() {
59 E : service_.Start(temp_dir_.path());
60 E : }
61 :
62 E : void StopService() {
63 E : service_.Stop();
64 E : }
65 :
66 E : void ReplayLogs(size_t files_expected) {
67 : // Stop the service if it's running.
68 E : ASSERT_NO_FATAL_FAILURE(StopService());
69 :
70 E : Parser parser;
71 E : ASSERT_TRUE(parser.Init(&handler_));
72 :
73 : // Queue up the trace file(s) we engendered.
74 : base::FileEnumerator enumerator(temp_dir_.path(),
75 : false,
76 E : base::FileEnumerator::FILES);
77 E : size_t num_files = 0;
78 E : while (true) {
79 E : base::FilePath trace_file = enumerator.Next();
80 E : if (trace_file.empty())
81 E : break;
82 E : ASSERT_TRUE(parser.OpenTraceFile(trace_file));
83 E : ++num_files;
84 E : }
85 :
86 E : EXPECT_EQ(files_expected, num_files);
87 :
88 E : if (num_files > 0)
89 E : ASSERT_TRUE(parser.Consume());
90 E : }
91 :
92 : protected:
93 : // The directory where trace file output will be written.
94 : base::ScopedTempDir temp_dir_;
95 :
96 : // The handler to which the trace file parser will delegate events.
97 : StrictMockParseEventHandler handler_;
98 :
99 : // Our call trace service process instance.
100 : testing::CallTraceService service_;
101 : };
102 :
103 : } // namespace
104 :
105 E : TEST_F(ProcessUtilsTest, LogModule) {
106 E : ASSERT_NO_FATAL_FAILURE(StartService());
107 :
108 : // Initialize the session.
109 E : trace::client::RpcSession session;
110 E : trace::client::TraceFileSegment segment;
111 E : std::string id = trace::client::GetInstanceIdForThisModule();
112 E : session.set_instance_id(base::UTF8ToWide(id));
113 E : session.CreateSession(&segment);
114 :
115 E : HMODULE self = ::GetModuleHandle(NULL);
116 E : DWORD process_id = ::GetCurrentProcessId();
117 E : DWORD thread_id = ::GetCurrentThreadId();
118 :
119 E : ASSERT_TRUE(LogModule(self, &session, &segment));
120 :
121 : // Logging an unloaded or invalid module should fail.
122 :
123 E : size_t kAllocSize = 4096;
124 : // Reserve an unmapped range of memory.
125 : void* unmapped =
126 E : ::VirtualAlloc(NULL, kAllocSize, MEM_RESERVE, PAGE_READWRITE);
127 E : ASSERT_NE(static_cast<void*>(NULL), unmapped);
128 :
129 : // Make sure logging the address as a module fails, logs nothing, but
130 : // doesn't crash. This simulates logging an unloaded module.
131 E : ASSERT_FALSE(LogModule(static_cast<HMODULE>(unmapped), &session, &segment));
132 :
133 : // Now allocate the first page, and make sure we don't log it absent the
134 : // magic numbers in a valid module. This simulates logging an unloaded
135 : // module, whose address space has been reused for data.
136 : ASSERT_NE(static_cast<void*>(NULL),
137 E : ::VirtualAlloc(unmapped, kAllocSize, MEM_COMMIT, PAGE_READWRITE));
138 E : ASSERT_FALSE(LogModule(static_cast<HMODULE>(unmapped), &session, &segment));
139 :
140 : // Free our alloc.
141 E : EXPECT_TRUE(::VirtualFree(unmapped, 0, MEM_RELEASE));
142 :
143 E : ASSERT_NO_FATAL_FAILURE(StopService());
144 :
145 E : EXPECT_CALL(handler_, OnProcessStarted(_, process_id, _));
146 : EXPECT_CALL(handler_, OnProcessAttach(_,
147 : process_id,
148 : thread_id,
149 E : ModuleAtAddress(self)));
150 E : EXPECT_CALL(handler_, OnProcessEnded(_, process_id));
151 :
152 E : ASSERT_NO_FATAL_FAILURE(ReplayLogs(1));
153 E : }
154 :
155 : } // namespace common
156 : } // namespace agent
|