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/asan_logger.h"
16 :
17 : #include "base/command_line.h"
18 : #include "base/environment.h"
19 : #include "base/logging.h"
20 : #include "base/process_util.h"
21 : #include "base/stringprintf.h"
22 : #include "base/utf_string_conversions.h"
23 : #include "base/debug/stack_trace.h"
24 : #include "base/memory/scoped_ptr.h"
25 : #include "syzygy/trace/rpc/logger_rpc.h"
26 : #include "syzygy/trace/rpc/rpc_helpers.h"
27 :
28 : namespace agent {
29 : namespace asan {
30 :
31 : namespace {
32 :
33 : using trace::client::GetInstanceString;
34 :
35 : AsanLogger* logger_instance = NULL;
36 :
37 : void InitExecutionContext(const CONTEXT& rtl_context,
38 E : ExecutionContext* exc_context) {
39 E : DCHECK(exc_context != NULL);
40 :
41 E : exc_context->edi = rtl_context.Edi;
42 E : exc_context->esi = rtl_context.Esi;
43 E : exc_context->ebx = rtl_context.Ebx;
44 E : exc_context->edx = rtl_context.Edx;
45 E : exc_context->ecx = rtl_context.Ecx;
46 E : exc_context->eax = rtl_context.Eax;
47 E : exc_context->ebp = rtl_context.Ebp;
48 E : exc_context->eip = rtl_context.Eip;
49 E : exc_context->seg_cs = rtl_context.SegCs;
50 E : exc_context->eflags = rtl_context.EFlags;
51 E : exc_context->esp = rtl_context.Esp;
52 E : exc_context->seg_ss = rtl_context.SegSs;
53 E : }
54 :
55 : void LogToFile(FILE* dest,
56 : const std::string& message,
57 E : const base::debug::StackTrace* trace) {
58 E : const char* format_str = "%s%s";
59 E : if (!message.empty() && message.back() != '\n')
60 i : format_str = "%s\n%s";
61 : ::fprintf(dest,
62 : format_str,
63 : message.c_str(),
64 E : trace == NULL ? "" : trace->ToString().c_str());
65 E : }
66 :
67 : } // namespace
68 :
69 E : AsanLogger::AsanLogger() {
70 E : }
71 :
72 E : void AsanLogger::Init() {
73 E : base::RouteStdioToConsole();
74 : bool success = rpc_binding_.Open(
75 : kLoggerRpcProtocol,
76 E : GetInstanceString(kLoggerRpcEndpointRoot, instance_id_));
77 :
78 : // TODO(rogerm): Add a notion of a session to the logger interface. Opening
79 : // a session (either here, or on first use) allows for better management
80 : // of symbol context across trace log messages for a given process.
81 E : if (success) {
82 E : const CommandLine* command_line = CommandLine::ForCurrentProcess();
83 : std::string message = base::StringPrintf(
84 : "PID=%d; cmd-line='%ls'\n",
85 : ::GetCurrentProcessId(),
86 E : command_line->GetCommandLineString().c_str());
87 : success = trace::client::InvokeRpc(
88 : &LoggerClient_Write,
89 : rpc_binding_.Get(),
90 E : reinterpret_cast<const unsigned char*>(message.c_str())).succeeded();
91 E : if (!success)
92 E : rpc_binding_.Close();
93 E : }
94 E : }
95 :
96 E : void AsanLogger::Write(const std::string& message) {
97 : // If we're bound to a logging endpoint, log the message there.
98 E : if (rpc_binding_.Get() != NULL) {
99 : trace::client::InvokeRpc(
100 : &LoggerClient_Write,
101 : rpc_binding_.Get(),
102 E : reinterpret_cast<const unsigned char*>(message.c_str()));
103 E : } else {
104 E : LogToFile(stderr, message, NULL);
105 : }
106 E : }
107 :
108 : void AsanLogger::WriteWithContext(const std::string& message,
109 E : const CONTEXT& context) {
110 : // If we're bound to a logging endpoint, log the message there.
111 E : if (rpc_binding_.Get() != NULL) {
112 E : ExecutionContext exec_context = {};
113 E : InitExecutionContext(context, &exec_context);
114 : trace::client::InvokeRpc(
115 : &LoggerClient_WriteWithContext,
116 : rpc_binding_.Get(),
117 : reinterpret_cast<const unsigned char*>(message.c_str()),
118 E : &exec_context);
119 E : } else {
120 : // Otherwise, log to stderr.
121 i : EXCEPTION_RECORD dummy_exc_record = {};
122 i : CONTEXT context_copy = context;
123 i : EXCEPTION_POINTERS pointers = { &dummy_exc_record, &context_copy };
124 i : base::debug::StackTrace trace(&pointers);
125 i : LogToFile(stderr, message, &trace);
126 i : }
127 E : }
128 :
129 : void AsanLogger::WriteWithStackTrace(const std::string& message,
130 : const void * const * trace_data,
131 E : size_t trace_length) {
132 : // If we're bound to a logging endpoint, log the message there.
133 E : if (rpc_binding_.Get() != NULL) {
134 : trace::client::InvokeRpc(
135 : &LoggerClient_WriteWithTrace,
136 : rpc_binding_.Get(),
137 : reinterpret_cast<const unsigned char*>(message.c_str()),
138 : reinterpret_cast<const DWORD*>(trace_data),
139 E : trace_length);
140 E : } else {
141 : // Otherwise, log to stderr.
142 i : base::debug::StackTrace trace(trace_data, trace_length);
143 i : LogToFile(stderr, message, &trace);
144 i : }
145 E : }
146 :
147 : } // namespace asan
148 : } // namespace agent
|