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