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 :
19 : #include "base/command_line.h"
20 : #include "base/environment.h"
21 : #include "base/logging.h"
22 : #include "base/debug/stack_trace.h"
23 : #include "base/process/launch.h"
24 : #include "base/strings/stringprintf.h"
25 : #include "base/strings/utf_string_conversions.h"
26 : #include "syzygy/common/rpc/helpers.h"
27 : #include "syzygy/trace/rpc/logger_rpc.h"
28 :
29 : namespace agent {
30 : namespace asan {
31 :
32 : namespace {
33 :
34 : using ::common::rpc::GetInstanceString;
35 :
36 : AsanLogger* logger_instance = NULL;
37 :
38 : void InitExecutionContext(const CONTEXT& rtl_context,
39 E : ExecutionContext* exc_context) {
40 E : DCHECK(exc_context != NULL);
41 : // TODO(loskutov): adapt for 64 bits
42 : #ifndef _WIN64
43 E : exc_context->edi = rtl_context.Edi;
44 E : exc_context->esi = rtl_context.Esi;
45 E : exc_context->ebx = rtl_context.Ebx;
46 E : exc_context->edx = rtl_context.Edx;
47 E : exc_context->ecx = rtl_context.Ecx;
48 E : exc_context->eax = rtl_context.Eax;
49 E : exc_context->ebp = rtl_context.Ebp;
50 E : exc_context->eip = rtl_context.Eip;
51 E : exc_context->seg_cs = rtl_context.SegCs;
52 E : exc_context->eflags = rtl_context.EFlags;
53 E : exc_context->esp = rtl_context.Esp;
54 E : exc_context->seg_ss = rtl_context.SegSs;
55 : #endif
56 E : }
57 :
58 : } // namespace
59 :
60 E : AsanLogger::AsanLogger() : log_as_text_(true), minidump_on_failure_(false) {
61 E : }
62 :
63 E : void AsanLogger::Init() {
64 E : bool success = rpc_binding_.Open(
65 : kLoggerRpcProtocol,
66 : GetInstanceString(kLoggerRpcEndpointRoot, instance_id_));
67 :
68 : // TODO(rogerm): Add a notion of a session to the logger interface. Opening
69 : // a session (either here, or on first use) allows for better management
70 : // of symbol context across trace log messages for a given process.
71 E : if (success) {
72 : const base::CommandLine* command_line =
73 E : base::CommandLine::ForCurrentProcess();
74 E : std::string message = base::StringPrintf(
75 : "PID=%d; cmd-line='%ls'\n",
76 : ::GetCurrentProcessId(),
77 : command_line->GetCommandLineString().c_str());
78 E : success = ::common::rpc::InvokeRpc(&LoggerClient_Write, rpc_binding_.Get(),
79 : reinterpret_cast<const unsigned char*>(
80 : message.c_str())).succeeded();
81 E : if (!success)
82 E : rpc_binding_.Close();
83 E : }
84 E : }
85 :
86 E : void AsanLogger::Stop() {
87 E : if (rpc_binding_.Get() != NULL) {
88 E : ::common::rpc::InvokeRpc(&LoggerClient_Stop, rpc_binding_.Get());
89 : }
90 E : }
91 :
92 E : void AsanLogger::Write(const std::string& message) {
93 : // If we're bound to a logging endpoint, log the message there.
94 E : if (rpc_binding_.Get() != NULL) {
95 E : ::common::rpc::InvokeRpc(
96 : &LoggerClient_Write, rpc_binding_.Get(),
97 : reinterpret_cast<const unsigned char*>(message.c_str()));
98 : }
99 E : }
100 :
101 : void AsanLogger::WriteWithContext(const std::string& message,
102 E : const CONTEXT& context) {
103 : // If we're bound to a logging endpoint, log the message there.
104 E : if (rpc_binding_.Get() != NULL) {
105 E : ExecutionContext exec_context = {};
106 E : InitExecutionContext(context, &exec_context);
107 E : ::common::rpc::InvokeRpc(
108 : &LoggerClient_WriteWithContext, rpc_binding_.Get(),
109 : reinterpret_cast<const unsigned char*>(message.c_str()), &exec_context);
110 : }
111 E : }
112 :
113 : void AsanLogger::WriteWithStackTrace(const std::string& message,
114 : const void * const * trace_data,
115 E : uint32_t trace_length) {
116 : // If we're bound to a logging endpoint, log the message there.
117 E : if (rpc_binding_.Get() != NULL) {
118 E : ::common::rpc::InvokeRpc(
119 : &LoggerClient_WriteWithTrace, rpc_binding_.Get(),
120 : reinterpret_cast<const unsigned char*>(message.c_str()),
121 : reinterpret_cast<const DWORD*>(trace_data), trace_length);
122 : }
123 E : }
124 :
125 : void AsanLogger::SaveMinidumpWithProtobufAndMemoryRanges(
126 : CONTEXT* context,
127 : AsanErrorInfo* error_info,
128 : const std::string& protobuf,
129 E : const MemoryRanges& memory_ranges) {
130 E : CHECK_NE(static_cast<CONTEXT*>(nullptr), context);
131 E : CHECK_NE(static_cast<AsanErrorInfo*>(nullptr), error_info);
132 :
133 E : if (rpc_binding_.Get() == NULL)
134 i : return;
135 :
136 : // Convert the memory ranges to arrays.
137 E : std::vector<const void*> base_addresses;
138 E : std::vector<size_t> range_lengths;
139 E : for (const auto& val : memory_ranges) {
140 E : base_addresses.push_back(val.first);
141 E : range_lengths.push_back(val.second);
142 E : }
143 :
144 E : EXCEPTION_RECORD exception = {};
145 E : exception.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
146 E : exception.ExceptionAddress = GetInstructionPointer(*context);
147 E : exception.NumberParameters = 2;
148 E : exception.ExceptionInformation[0] = reinterpret_cast<ULONG_PTR>(context);
149 E : exception.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(error_info);
150 :
151 E : const EXCEPTION_POINTERS pointers = { &exception, context };
152 E : ::common::rpc::InvokeRpc(
153 : &LoggerClient_SaveMinidumpWithProtobufAndMemoryRanges, rpc_binding_.Get(),
154 : ::GetCurrentThreadId(), reinterpret_cast<unsigned long>(&pointers),
155 : reinterpret_cast<const byte*>(protobuf.data()),
156 : static_cast<unsigned long>(protobuf.size()),
157 : reinterpret_cast<const unsigned long*>(base_addresses.data()),
158 : reinterpret_cast<const unsigned long*>(range_lengths.data()),
159 : static_cast<uint32_t>(memory_ranges.size()));
160 E : }
161 :
162 : } // namespace asan
163 : } // namespace agent
|