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 : // This file implements the RPC stubs which bind the LoggerService RPC
16 : // handlers to a Logger instance.
17 :
18 : #include "syzygy/trace/agent_logger/agent_logger_rpc_impl.h"
19 :
20 : #include <windows.h>
21 : #include <winnt.h>
22 :
23 : #include "base/process/process.h"
24 : #include "base/win/scoped_handle.h"
25 : #include "syzygy/common/com_utils.h"
26 : #include "syzygy/common/rpc/helpers.h"
27 : #include "syzygy/trace/agent_logger/agent_logger.h"
28 : #include "syzygy/trace/rpc/logger_rpc.h"
29 :
30 : namespace {
31 :
32 : using base::ProcessId;
33 : using base::win::ScopedHandle;
34 : using trace::agent_logger::RpcLoggerInstanceManager;
35 : using trace::agent_logger::AgentLogger;
36 :
37 : bool GetClientInfo(handle_t binding,
38 : base::ProcessId* pid,
39 E : base::win::ScopedHandle* handle) {
40 E : DCHECK(pid);
41 E : DCHECK(handle);
42 :
43 E : base::ProcessId the_pid = ::common::rpc::GetClientProcessID(binding);
44 E : if (!the_pid)
45 i : return false;
46 :
47 : // Open and return the handle to the process.
48 : static const DWORD kFlags =
49 : PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ;
50 E : handle->Set(::OpenProcess(kFlags, FALSE, the_pid));
51 E : if (!handle->IsValid()) {
52 i : DWORD error = ::GetLastError();
53 i : LOG(ERROR) << "Failed to open PID=" << the_pid << ": "
54 : << ::common::LogWe(error) << ".";
55 i : return false;
56 : }
57 :
58 : // And we're done.
59 E : *pid = the_pid;
60 E : return true;
61 E : }
62 :
63 E : void InitContext(const ExecutionContext* ext_ctx, CONTEXT* ctx) {
64 E : DCHECK(ext_ctx != NULL);
65 E : DCHECK(ctx != NULL);
66 :
67 E : ::memset(ctx, 0, sizeof(*ctx));
68 E : ctx->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
69 :
70 : // Populate the integer registers.
71 E : ctx->Edi = ext_ctx->edi;
72 E : ctx->Esi = ext_ctx->esi;
73 E : ctx->Ebx = ext_ctx->ebx;
74 E : ctx->Edx = ext_ctx->edx;
75 E : ctx->Ecx = ext_ctx->ecx;
76 E : ctx->Eax = ext_ctx->eax;
77 :
78 : // Populate the control registers.
79 E : ctx->Ebp = ext_ctx->ebp;
80 E : ctx->Eip = ext_ctx->eip;
81 E : ctx->SegCs = ext_ctx->seg_cs;
82 E : ctx->EFlags = ext_ctx->eflags;
83 E : ctx->Esp = ext_ctx->esp;
84 E : ctx->SegSs = ext_ctx->seg_ss;
85 E : }
86 :
87 : } // namespace
88 :
89 : // The instance to which the RPC callbacks are bound.
90 : AgentLogger* RpcLoggerInstanceManager::instance_ = NULL;
91 :
92 : // RPC entrypoint for AgentLogger::Write().
93 : boolean LoggerService_Write(
94 : /* [in] */ handle_t binding,
95 E : /* [string][in] */ const unsigned char *text) {
96 E : if (binding == NULL || text == NULL) {
97 i : LOG(ERROR) << "Invalid input parameter(s).";
98 i : return false;
99 : }
100 :
101 : // Get the logger instance.
102 E : AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
103 :
104 : // Write the log message.
105 E : std::string message(reinterpret_cast<const char*>(text));
106 E : if (!instance->Write(message))
107 i : return false;
108 :
109 : // And we're done.
110 E : return true;
111 E : }
112 :
113 : boolean LoggerService_WriteWithContext(
114 : /* [in] */ handle_t binding,
115 : /* [in, string] */ const unsigned char* text,
116 E : /* [in */ const ExecutionContext* exc_context ) {
117 E : if (binding == NULL || text == NULL || exc_context == NULL) {
118 i : LOG(ERROR) << "Invalid input parameter(s).";
119 i : return false;
120 : }
121 :
122 : // Get the caller's process info.
123 E : ProcessId pid = 0;
124 E : ScopedHandle handle;
125 E : if (!GetClientInfo(binding, &pid, &handle))
126 i : return false;
127 :
128 : // Get the logger instance.
129 E : AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
130 :
131 : // Capture the stack trace for the caller's context.
132 E : CONTEXT context = {};
133 E : InitContext(exc_context, &context);
134 E : std::vector<DWORD> trace_data;
135 E : if (!instance->CaptureRemoteTrace(handle, &context, &trace_data)) {
136 i : return false;
137 : }
138 :
139 : // Create the log message.
140 E : std::string message(reinterpret_cast<const char*>(text));
141 : if (!instance->AppendTrace(
142 E : handle, trace_data.data(), trace_data.size(), &message)) {
143 i : return false;
144 : }
145 :
146 : // Write the log message.
147 E : if (!instance->Write(message))
148 i : return false;
149 :
150 : // And we're done.
151 E : return true;
152 E : }
153 :
154 : boolean LoggerService_WriteWithTrace(
155 : /* [in] */ handle_t binding,
156 : /* [in, string] */ const unsigned char* text,
157 : /* [in, size_is(trace_length)] */ const unsigned long* trace_data,
158 E : /* [in] */ LONG trace_length) {
159 E : if (binding == NULL || text == NULL || trace_data == NULL) {
160 i : LOG(ERROR) << "Invalid input parameter(s).";
161 i : return false;
162 : }
163 :
164 : // Get the caller's process info.
165 E : ProcessId pid = 0;
166 E : ScopedHandle handle;
167 E : if (!GetClientInfo(binding, &pid, &handle))
168 i : return false;
169 :
170 : // Get the logger instance.
171 E : AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
172 :
173 : // Create the log message.
174 E : std::string message(reinterpret_cast<const char*>(text));
175 E : if (!instance->AppendTrace(handle, trace_data, trace_length, &message))
176 i : return false;
177 :
178 : // Write the log message.
179 E : if (!instance->Write(message))
180 i : return false;
181 :
182 : // And we're done.
183 E : return true;
184 E : }
185 :
186 : // RPC entrypoint for AgentLogger::SaveMinidump().
187 : boolean LoggerService_SaveMiniDump(
188 : /* [in] */ handle_t binding,
189 : /* [in] */ unsigned long thread_id,
190 : /* [in] */ unsigned long exception,
191 E : /* [in] */ unsigned long flags) {
192 E : if (binding == NULL) {
193 i : LOG(ERROR) << "Invalid input parameter(s).";
194 i : return false;
195 : }
196 :
197 : // Get the caller's process info.
198 E : ProcessId pid = 0;
199 E : ScopedHandle handle;
200 E : if (!GetClientInfo(binding, &pid, &handle))
201 i : return false;
202 :
203 E : AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
204 E : if (!instance->SaveMiniDump(handle, pid, thread_id, exception, flags))
205 i : return false;
206 :
207 E : return true;
208 E : }
209 :
210 : // RPC entrypoint for AgentLogger::Stop().
211 E : boolean LoggerService_Stop(/* [in] */ handle_t binding) {
212 E : if (binding == NULL) {
213 i : LOG(ERROR) << "Invalid input parameter(s).";
214 i : return false;
215 : }
216 :
217 : // Get the caller's process info.
218 E : ProcessId pid = 0;
219 E : ScopedHandle handle;
220 E : if (!GetClientInfo(binding, &pid, &handle))
221 i : return false;
222 :
223 E : AgentLogger* instance = RpcLoggerInstanceManager::GetInstance();
224 E : if (!instance->Stop())
225 i : return false;
226 :
227 E : return true;
228 E : }
|