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