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/asan/logger.h"
16 :
17 : #include <memory>
18 : #include <string>
19 :
20 : #include "base/bind.h"
21 : #include "base/bind_helpers.h"
22 : #include "base/environment.h"
23 : #include "base/files/file_enumerator.h"
24 : #include "base/files/file_path.h"
25 : #include "base/files/file_util.h"
26 : #include "base/files/scoped_temp_dir.h"
27 : #include "base/strings/string_util.h"
28 : #include "base/strings/stringprintf.h"
29 : #include "base/strings/utf_string_conversions.h"
30 : #include "gmock/gmock.h"
31 : #include "gtest/gtest.h"
32 : #include "syzygy/agent/asan/runtime.h"
33 : #include "syzygy/crashdata/crashdata.h"
34 : #include "syzygy/trace/agent_logger/agent_logger.h"
35 : #include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"
36 : #include "syzygy/trace/protocol/call_trace_defs.h"
37 :
38 : namespace agent {
39 : namespace asan {
40 :
41 : namespace {
42 :
43 : using testing::Return;
44 :
45 : class TestAsanLogger : public AsanLogger {
46 : public:
47 : using AsanLogger::instance_id_;
48 : using AsanLogger::rpc_binding_;
49 : };
50 :
51 : class AsanLoggerTest : public testing::Test {
52 : public:
53 E : AsanLoggerTest() {
54 E : EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
55 E : temp_path_ = temp_dir_.path().Append(L"log.txt");
56 :
57 : // Setup the instance id.
58 E : instance_id_ = base::StringPrintf(L"%d", ::GetCurrentProcessId());
59 E : }
60 :
61 E : MOCK_METHOD1(LoggerStoppedCallback, bool(trace::common::Service*));
62 :
63 : protected:
64 : base::ScopedTempDir temp_dir_;
65 : base::FilePath temp_path_;
66 : std::wstring instance_id_;
67 : TestAsanLogger client_;
68 : };
69 :
70 : } // namespace
71 :
72 E : TEST_F(AsanLoggerTest, EndToEnd) {
73 E : const std::string kMessage("This is the test message\n");
74 :
75 : {
76 : // Setup a log file destination.
77 E : base::ScopedFILE destination(base::OpenFile(temp_path_, "wb"));
78 :
79 : // Start up the logging service.
80 E : trace::agent_logger::AgentLogger server;
81 E : trace::agent_logger::RpcLoggerInstanceManager instance_manager(&server);
82 E : server.set_instance_id(instance_id_);
83 E : server.set_destination(destination.get());
84 E : server.set_minidump_dir(temp_dir_.path());
85 E : ASSERT_TRUE(server.Start());
86 :
87 : // Use the AsanLogger client.
88 E : client_.set_instance_id(instance_id_);
89 E : client_.set_log_as_text(true);
90 E : client_.set_minidump_on_failure(true);
91 E : client_.Init();
92 E : ASSERT_EQ(instance_id_, client_.instance_id_);
93 E : ASSERT_TRUE(client_.rpc_binding_.Get() != NULL);
94 :
95 : // Generate a minidump.
96 E : CONTEXT ctx = {};
97 E : ::RtlCaptureContext(&ctx);
98 E : AsanErrorInfo info = {};
99 E : crashdata::Value protobuf;
100 E : crashdata::Dictionary* dict = crashdata::ValueGetDict(&protobuf);
101 : crashdata::LeafGetAddress(crashdata::DictAddLeaf("foo", dict))
102 E : ->set_address(0xDABBAD00);
103 : crashdata::LeafGetAddress(crashdata::DictAddLeaf("bar", dict))
104 E : ->set_address(0xDEADC0DE);
105 E : std::string protobuf_str;
106 E : ASSERT_TRUE(protobuf.SerializeToString(&protobuf_str));
107 E : MemoryRanges memory_ranges;
108 E : memory_ranges.push_back(
109 : std::make_pair(protobuf_str.data(), protobuf_str.size()));
110 E : client_.SaveMinidumpWithProtobufAndMemoryRanges(&ctx, &info, protobuf_str,
111 : memory_ranges);
112 E : client_.Write(kMessage);
113 :
114 : // Shutdown the logging service.
115 E : ASSERT_TRUE(server.Stop());
116 E : ASSERT_TRUE(server.Join());
117 E : }
118 :
119 : // Inspect the log file contents.
120 E : std::string content;
121 E : ASSERT_TRUE(base::ReadFileToString(temp_path_, &content));
122 E : ASSERT_THAT(content, testing::EndsWith(kMessage));
123 :
124 : // We should have exactly one minidump in the temp directory.
125 : using base::FileEnumerator;
126 E : FileEnumerator fe(temp_dir_.path(), false, FileEnumerator::FILES, L"*.dmp");
127 E : base::FilePath minidump(fe.Next());
128 E : EXPECT_FALSE(minidump.empty());
129 E : EXPECT_TRUE(fe.Next().empty());
130 :
131 : // TODO(rogerm): Inspect the contents of the minidump.
132 E : }
133 :
134 E : TEST_F(AsanLoggerTest, Stop) {
135 : // Setup a log file destination.
136 E : base::ScopedFILE destination(base::OpenFile(temp_path_, "wb"));
137 :
138 : // Start up the logging service.
139 E : trace::agent_logger::AgentLogger server;
140 E : trace::agent_logger::RpcLoggerInstanceManager instance_manager(&server);
141 E : server.set_instance_id(instance_id_);
142 E : server.set_destination(destination.get());
143 E : server.set_stopped_callback(
144 : base::Bind(&AsanLoggerTest::LoggerStoppedCallback,
145 : base::Unretained(this)));
146 E : ASSERT_TRUE(server.Start());
147 :
148 : // Use the AsanLogger client.
149 E : client_.set_instance_id(instance_id_);
150 E : client_.Init();
151 E : ASSERT_EQ(instance_id_, client_.instance_id_);
152 E : ASSERT_TRUE(client_.rpc_binding_.Get() != NULL);
153 :
154 : trace::common::Service* server_base = static_cast<trace::common::Service*>(
155 E : &server);
156 : EXPECT_CALL(*this, LoggerStoppedCallback(server_base)).Times(1).
157 E : WillOnce(Return(true));
158 E : client_.Stop();
159 E : ASSERT_TRUE(server.Join());
160 E : }
161 :
162 : } // namespace asan
163 : } // namespace agent
|