Coverage for /Syzygy/trace/agent_logger/agent_logger.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
77.6%2182810.C++source

Line-by-line coverage:

   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 defines the trace::agent_logger::Logger class which implements the
  16    :  // Logger RPC interface.
  17    :  
  18    :  #include "syzygy/trace/agent_logger/agent_logger.h"
  19    :  
  20    :  #include <windows.h>  // NOLINT
  21    :  #include <dbghelp.h>
  22    :  #include <psapi.h>
  23    :  
  24    :  #include "base/bind.h"
  25    :  #include "base/strings/string_util.h"
  26    :  #include "base/strings/stringprintf.h"
  27    :  #include "base/win/scoped_handle.h"
  28    :  #include "syzygy/common/com_utils.h"
  29    :  #include "syzygy/common/dbghelp_util.h"
  30    :  #include "syzygy/common/rpc/helpers.h"
  31    :  #include "syzygy/kasko/minidump.h"
  32    :  #include "syzygy/kasko/minidump_request.h"
  33    :  #include "syzygy/kasko/api/client.h"
  34    :  #include "syzygy/pe/find.h"
  35    :  
  36    :  namespace trace {
  37    :  namespace agent_logger {
  38    :  
  39    :  namespace {
  40    :  
  41    :  using ::common::rpc::GetInstanceString;
  42    :  
  43    :  // A helper class to manage a SYMBOL_INFO structure.
  44    :  template <size_t max_name_len>
  45    :  class SymbolInfo {
  46    :   public:
  47  E :    SymbolInfo() {
  48    :      static_assert(max_name_len > 0, "Maximum name length should be > 0.");
  49    :      static_assert(
  50    :          sizeof(buf_) - sizeof(info_) >= max_name_len * sizeof(wchar_t),
  51    :          "Not enough buffer space for max_name_len wchars");
  52    :  
  53  E :      ::memset(buf_, 0, sizeof(buf_));
  54  E :      info_.SizeOfStruct = sizeof(info_);
  55  E :      info_.MaxNameLen = max_name_len;
  56  E :    }
  57    :  
  58  E :    PSYMBOL_INFO Get() { return &info_; }
  59    :  
  60  E :    PSYMBOL_INFO operator->() { return &info_; }
  61    :  
  62    :   private:
  63    :    // SYMBOL_INFO is a variable length structure ending with a string (the
  64    :    // name of the symbol). The SYMBOL_INFO struct itself only declares the
  65    :    // first byte of the Name array, the rest we reserve by holding it in
  66    :    // union with a properly sized underlying buffer.
  67    :    union {
  68    :      SYMBOL_INFO info_;
  69    :      char buf_[sizeof(SYMBOL_INFO) + max_name_len * sizeof(wchar_t)];
  70    :    };
  71    :  };
  72    :  
  73    :  void GetSymbolInfo(HANDLE process,
  74    :                     DWORD frame_ptr,
  75    :                     std::string* name,
  76  E :                     DWORD64* offset) {
  77  E :    DCHECK(frame_ptr != NULL);
  78  E :    DCHECK(name != NULL);
  79  E :    DCHECK(offset != NULL);
  80    :  
  81    :    // Constants we'll need later.
  82    :    static const size_t kMaxNameLength = 256;
  83  E :    SymbolInfo<kMaxNameLength> symbol;
  84    :  
  85    :    // Lookup the symbol by address.
  86  E :    if (::SymFromAddr(process, frame_ptr, offset, symbol.Get())) {
  87  E :      base::SStringPrintf(name, "%s+%ld", symbol->Name, *offset);
  88  E :    } else {
  89  E :      base::SStringPrintf(name, "(unknown)+%ld", *offset);
  90    :    }
  91  E :  }
  92    :  
  93  E :  void GetLineInfo(HANDLE process, DWORD_PTR frame, std::string* line_info) {
  94  E :    DCHECK(frame != NULL);
  95  E :    DCHECK(line_info != NULL);
  96    :  
  97  E :    DWORD line_displacement = 0;
  98  E :    IMAGEHLP_LINE64 line = {};
  99  E :    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
 100  E :    if (::SymGetLineFromAddr64(process, frame, &line_displacement, &line)) {
 101  E :      base::SStringPrintf(line_info, "%s:%d", line.FileName, line.LineNumber);
 102  E :    } else {
 103  E :      line_info->clear();
 104    :    }
 105  E :  }
 106    :  
 107    :  // A callback function used with the StackWalk64 function. It is called when
 108    :  // StackWalk64 needs to read memory from the address space of the process.
 109    :  // http://msdn.microsoft.com/en-us/library/windows/desktop/ms680559.aspx
 110    :  BOOL CALLBACK ReadProcessMemoryProc64(HANDLE process,
 111    :                                        DWORD64 base_address_64,
 112    :                                        PVOID buffer,
 113    :                                        DWORD size,
 114  E :                                        LPDWORD bytes_read) {
 115  E :    DCHECK(buffer != NULL);
 116  E :    DCHECK(bytes_read != NULL);
 117  E :    *bytes_read = 0;
 118  E :    LPCVOID base_address = reinterpret_cast<LPCVOID>(base_address_64);
 119  E :    if (::ReadProcessMemory(process, base_address, buffer, size, bytes_read))
 120  E :      return TRUE;
 121    :  
 122    :    // Maybe it was just a partial read, which isn't fatal.
 123  E :    DWORD error = ::GetLastError();
 124  E :    if (error == ERROR_PARTIAL_COPY)
 125  E :      return TRUE;
 126    :  
 127    :    // Nope, it was a real error.
 128  i :    LOG(ERROR) << "Failed to read process memory: " << ::common::LogWe(error)
 129    :               << ".";
 130  i :    return FALSE;
 131  E :  }
 132    :  
 133    :  }  // namespace
 134    :  
 135    :  AgentLogger::AgentLogger()
 136  E :      : trace::common::Service(L"Logger"),
 137  E :        destination_(NULL),
 138  E :        symbolize_stack_traces_(true) {
 139  E :  }
 140    :  
 141  E :  AgentLogger::~AgentLogger() {
 142  E :    if (state() != kStopped) {
 143  i :      ignore_result(Stop());
 144  i :      ignore_result(Join());
 145    :    }
 146  E :  }
 147    :  
 148  E :  bool AgentLogger::StartImpl() {
 149  E :    LOG(INFO) << "Starting the logging service.";
 150    :  
 151  E :    if (!InitRpc())
 152  i :      return false;
 153    :  
 154  E :    if (!StartRpc())
 155  i :      return false;
 156    :  
 157  E :    return true;
 158  E :  }
 159    :  
 160  E :  bool AgentLogger::StopImpl() {
 161  E :    if (!StopRpc())
 162  i :      return false;
 163  E :    return true;
 164  E :  }
 165    :  
 166  E :  bool AgentLogger::JoinImpl() {
 167    :    // Finish processing all RPC events. If Stop() has previously been called
 168    :    // this will simply ensure that all outstanding requests are handled. If
 169    :    // Stop has not been called, this will continue (i.e., block) handling events
 170    :    // until someone else calls Stop() in another thread.
 171  E :    if (!FinishRpc())
 172  i :      return false;
 173    :  
 174  E :    return true;
 175  E :  }
 176    :  
 177    :  bool AgentLogger::AppendTrace(HANDLE process,
 178    :                                const DWORD* trace_data,
 179    :                                size_t trace_length,
 180  E :                                std::string* message) {
 181  E :    DCHECK(trace_data != NULL);
 182  E :    DCHECK(message != NULL);
 183    :  
 184    :    // If we don't want to symbolize the stack traces then we just dump the
 185    :    // frame addresses.
 186  E :    if (!symbolize_stack_traces_) {
 187  i :      for (size_t i = 0; i < trace_length; ++i) {
 188  i :        DWORD frame_ptr = trace_data[i];
 189  i :        base::StringAppendF(message,
 190    :                            "    #%d 0x%012llx\n",
 191    :                            i,
 192    :                            frame_ptr);
 193  i :      }
 194  i :      return true;
 195    :    }
 196    :  
 197    :    // TODO(rogerm): Add an RPC session to the logger and its interface. This
 198    :    //     would serialize calls per process and provide a convenient mechanism
 199    :    //     for ensuring SymInitialize/Cleanup are called exactly once per client
 200    :    //     process.
 201    :  
 202  E :    base::AutoLock auto_lock(symbol_lock_);
 203    :  
 204    :    // Make a unique "handle" for this use of the symbolizer.
 205  E :    base::win::ScopedHandle unique_handle(
 206    :        ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
 207    :                      ::GetCurrentProcessId()));
 208    :  
 209    :    // Initializes the symbols for the process:
 210    :    //     - Defer symbol load until they're needed
 211    :    //     - Use undecorated names
 212    :    //     - Get line numbers
 213  E :    ::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
 214  E :    if (!::common::SymInitialize(unique_handle.Get(), NULL, true))
 215  i :      return false;
 216    :  
 217    :    // Try to find the PDB of the running process, if it's found its path will be
 218    :    // appended to the current symbol search path. It is necessary because the
 219    :    // default search path doesn't include the directory of the caller by default.
 220    :    // TODO(sebmarchand): Also append the path of the PDBs of the modules loaded
 221    :    //     by the running process.
 222    :    WCHAR temp_path[MAX_PATH];
 223  E :    if (::GetModuleFileNameEx(process, NULL, temp_path, MAX_PATH) != 0) {
 224  E :      base::FilePath module_path(temp_path);
 225  E :      base::FilePath temp_pdb_path;
 226  E :      if (pe::FindPdbForModule(module_path, &temp_pdb_path)) {
 227    :        char current_search_path[1024];
 228  E :        if (!::SymGetSearchPath(unique_handle.Get(), current_search_path,
 229    :                                arraysize(current_search_path))) {
 230  i :          DWORD error = ::GetLastError();
 231  i :          LOG(ERROR) << "Unable to get the current symbol search path: "
 232    :                     << ::common::LogWe(error);
 233  i :          return false;
 234    :        }
 235  E :        std::string new_pdb_search_path = std::string(current_search_path) + ";" +
 236    :                                          temp_pdb_path.DirName().AsUTF8Unsafe();
 237  E :        if (!::SymSetSearchPath(unique_handle.Get(),
 238    :                                new_pdb_search_path.c_str())) {
 239  i :          LOG(ERROR) << "Unable to set the symbol search path.";
 240  i :          return false;
 241    :        }
 242  E :      }
 243  E :    }
 244    :  
 245    :    // Append each line of the trace to the message string.
 246  E :    for (size_t i = 0; i < trace_length; ++i) {
 247  E :      DWORD frame_ptr = trace_data[i];
 248  E :      DWORD64 offset = 0;
 249  E :      std::string symbol_name;
 250  E :      std::string line_info;
 251    :  
 252  E :      GetSymbolInfo(unique_handle.Get(), frame_ptr, &symbol_name, &offset);
 253  E :      GetLineInfo(unique_handle.Get(), frame_ptr, &line_info);
 254    :  
 255  E :      base::StringAppendF(message,
 256    :                          "    #%d 0x%012llx in %s%s%s\n",
 257    :                          i,
 258    :                          frame_ptr + offset,
 259    :                          symbol_name.c_str(),
 260    :                          line_info.empty() ? "" : " ",
 261    :                          line_info.c_str());
 262  E :    }
 263    :  
 264  E :    if (!::SymCleanup(unique_handle.Get())) {
 265  i :      DWORD error = ::GetLastError();
 266  i :      LOG(ERROR) << "SymCleanup failed: " << ::common::LogWe(error) << ".";
 267  i :      return false;
 268    :    }
 269    :  
 270  E :    return true;
 271  E :  }
 272    :  
 273    :  bool AgentLogger::CaptureRemoteTrace(HANDLE process,
 274    :                                       CONTEXT* context,
 275  E :                                       std::vector<DWORD>* trace_data) {
 276  E :    DCHECK(context != NULL);
 277  E :    DCHECK(trace_data != NULL);
 278    :  
 279    :    // TODO(rogerm): Add an RPC session to the logger and its interface. This
 280    :    //     would serialize calls per process and provide a convenient mechanism
 281    :    //     for ensuring SymInitialize/Cleanup are called exactly once per client
 282    :    //     process.
 283    :  
 284  E :    trace_data->clear();
 285  E :    trace_data->reserve(64);
 286    :  
 287    :    // If we don't want to symbolize the stack trace then there's no reason to
 288    :    // capture it.
 289  E :    if (!symbolize_stack_traces_) {
 290  i :      return true;
 291    :    }
 292    :  
 293  E :    base::AutoLock auto_lock(symbol_lock_);
 294    :  
 295    :    // Make a unique "handle" for this use of the symbolizer.
 296  E :    base::win::ScopedHandle unique_handle(
 297    :        ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
 298    :                      ::GetCurrentProcessId()));
 299    :  
 300    :    // Initializes the symbols for the process:
 301    :    //     - Defer symbol load until they're needed
 302    :    //     - Use undecorated names
 303    :    //     - Get line numbers
 304  E :    ::SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
 305  E :    if (!::common::SymInitialize(unique_handle.Get(), NULL, true))
 306  i :      return false;
 307    :  
 308    :    // Initialize a stack frame structure.
 309    :    STACKFRAME64 stack_frame;
 310  E :    ::memset(&stack_frame, 0, sizeof(stack_frame));
 311    :  #if defined(_WIN64)
 312    :    int machine_type = IMAGE_FILE_MACHINE_AMD64;
 313    :    stack_frame.AddrPC.Offset = context->Rip;
 314    :    stack_frame.AddrFrame.Offset = context->Rbp;
 315    :    stack_frame.AddrStack.Offset = context->Rsp;
 316    :  #else
 317  E :    int machine_type = IMAGE_FILE_MACHINE_I386;
 318  E :    stack_frame.AddrPC.Offset = context->Eip;
 319  E :    stack_frame.AddrFrame.Offset = context->Ebp;
 320  E :    stack_frame.AddrStack.Offset = context->Esp;
 321    :  #endif
 322  E :    stack_frame.AddrPC.Mode = AddrModeFlat;
 323  E :    stack_frame.AddrFrame.Mode = AddrModeFlat;
 324  E :    stack_frame.AddrStack.Mode = AddrModeFlat;
 325    :  
 326    :    // Walk the stack.
 327  E :    while (::StackWalk64(machine_type, unique_handle.Get(), NULL, &stack_frame,
 328    :                         context, &ReadProcessMemoryProc64,
 329    :                         &::SymFunctionTableAccess64, &::SymGetModuleBase64,
 330    :                         NULL)) {
 331  E :      trace_data->push_back(stack_frame.AddrPC.Offset);
 332  E :    }
 333    :  
 334  E :    if (!::SymCleanup(unique_handle.Get())) {
 335  i :      DWORD error = ::GetLastError();
 336  i :      LOG(ERROR) << "SymCleanup failed: " << ::common::LogWe(error) << ".";
 337  i :      return false;
 338    :    }
 339    :  
 340    :    // And we're done.
 341  E :    return true;
 342  E :  }
 343    :  
 344  E :  bool AgentLogger::Write(const base::StringPiece& message) {
 345  E :    DCHECK(destination_ != NULL);
 346    :  
 347  E :    if (message.empty())
 348  E :      return true;
 349    :  
 350  E :    base::AutoLock auto_lock(write_lock_);
 351    :  
 352  E :    size_t chars_written = ::fwrite(message.data(),
 353    :                                    sizeof(std::string::value_type),
 354    :                                    message.size(),
 355    :                                    destination_);
 356    :  
 357  E :    if (chars_written != message.size()) {
 358  i :      LOG(ERROR) << "Failed to write log message.";
 359  i :      return false;
 360    :    }
 361    :  
 362  E :    if (message[message.size() - 1] != '\n' &&
 363    :        ::fwrite("\n", 1, 1, destination_) != 1) {
 364  i :      LOG(ERROR) << "Failed to append trailing newline.";
 365  i :      return false;
 366    :    }
 367    :  
 368  E :    ::fflush(destination_);
 369    :  
 370  E :    return true;
 371  E :  }
 372    :  
 373    :  bool AgentLogger::SaveMinidumpWithProtobufAndMemoryRanges(
 374    :      HANDLE process,
 375    :      base::ProcessId pid,
 376    :      DWORD tid,
 377    :      DWORD exc_ptr,
 378    :      const byte* protobuf,
 379    :      size_t protobuf_length,
 380    :      const void* const* memory_ranges_base_addresses,
 381    :      const size_t* memory_ranges_lengths,
 382  E :      size_t memory_ranges_count) {
 383  E :    DCHECK_NE(static_cast<const byte*>(nullptr), protobuf);
 384  E :    DCHECK_NE(static_cast<const void* const*>(nullptr),
 385  E :              memory_ranges_base_addresses);
 386  E :    DCHECK_NE(static_cast<const size_t*>(nullptr), memory_ranges_lengths);
 387    :  
 388    :    // Copy the memory ranges into a vector.
 389  E :    std::vector<kasko::api::MemoryRange> memory_ranges;
 390  E :    for (size_t i = 0; i < memory_ranges_count; ++i) {
 391  E :      kasko::api::MemoryRange memory_range = {memory_ranges_base_addresses[i],
 392  E :                                              memory_ranges_lengths[i]};
 393  E :      memory_ranges.push_back(memory_range);
 394  E :    }
 395    :  
 396  E :    kasko::MinidumpRequest request;
 397  E :    request.client_exception_pointers = true;
 398  E :    request.exception_info_address = exc_ptr;
 399  E :    if (protobuf_length) {
 400    :      kasko::MinidumpRequest::CustomStream custom_stream = {
 401  E :          kasko::api::kProtobufStreamType, protobuf, protobuf_length};
 402  E :      request.custom_streams.push_back(custom_stream);
 403    :    }
 404    :  
 405  E :    request.type = kasko::MinidumpRequest::LARGER_DUMP_TYPE;
 406    :  
 407  E :    DCHECK(!minidump_dir_.empty());
 408    :    // Create a temporary file to which to write the minidump. We'll rename it
 409    :    // to something recognizable when we're finished writing to it.
 410  E :    base::FilePath temp_file_path;
 411  E :    if (!base::CreateTemporaryFileInDir(minidump_dir_, &temp_file_path)) {
 412  i :      LOG(ERROR) << "Could not create mini dump file in "
 413    :                 << minidump_dir_.value();
 414  i :      return false;
 415    :    }
 416    :  
 417    :    {
 418  E :      base::AutoLock auto_lock(symbol_lock_);
 419  E :      base::win::ScopedHandle target_process_handle(::OpenProcess(
 420    :          GetRequiredAccessForMinidumpType(request.type), FALSE, pid));
 421  E :      if (!target_process_handle.IsValid()) {
 422  i :        LOG(ERROR) << "Failed to open target process: " << ::common::LogWe()
 423    :                   << ".";
 424  i :        return false;
 425    :      }
 426  E :      CHECK(kasko::GenerateMinidump(temp_file_path, target_process_handle.Get(),
 427    :                                    tid, request));
 428  E :    }
 429    :  
 430    :    // Rename the temporary file so that its recognizable as a dump.
 431  E :    base::FilePath final_name(
 432    :        base::StringPrintf(L"minidump-%08u-%08u-%08u.dmp",
 433    :                           pid, tid, ::GetTickCount()));
 434  E :    base::FilePath final_path = minidump_dir_.Append(final_name);
 435  E :    if (base::Move(temp_file_path, final_path)) {
 436  E :      std::string log_msg = base::StringPrintf(
 437    :          "A minidump has been written to %s.",
 438    :          final_path.AsUTF8Unsafe().c_str());
 439  E :      Write(log_msg);
 440  E :    } else {
 441  i :      DWORD error = ::GetLastError();
 442  i :      LOG(ERROR) << "Failed to move dump file to final location "
 443    :                 << ::common::LogWe(error) << ".";
 444  i :      return false;
 445    :    }
 446    :  
 447  E :    return true;
 448  E :  }
 449    :  
 450  E :  bool AgentLogger::InitRpc() {
 451  E :    RPC_STATUS status = RPC_S_OK;
 452    :  
 453    :    // Initialize the RPC protocol we want to use.
 454  E :    std::wstring protocol(kLoggerRpcProtocol);
 455  E :    std::wstring endpoint(
 456    :        GetInstanceString(kLoggerRpcEndpointRoot, instance_id()));
 457    :  
 458  E :    VLOG(1) << "Initializing RPC endpoint '" << endpoint << "' "
 459    :            << "using the '" << protocol << "' protocol.";
 460  E :    status = ::RpcServerUseProtseqEp(
 461    :        ::common::rpc::AsRpcWstr(&protocol[0]), RPC_C_LISTEN_MAX_CALLS_DEFAULT,
 462    :        ::common::rpc::AsRpcWstr(&endpoint[0]), NULL /* Security descriptor. */);
 463  E :    if (status != RPC_S_OK && status != RPC_S_DUPLICATE_ENDPOINT) {
 464  i :      LOG(ERROR) << "Failed to init RPC protocol: " << ::common::LogWe(status)
 465    :                 << ".";
 466  i :      return false;
 467    :    }
 468    :  
 469    :    // Register the logger interface.
 470  E :    VLOG(1) << "Registering the Logger interface.";
 471  E :    status = ::RpcServerRegisterIf(
 472    :        LoggerService_Logger_v1_0_s_ifspec, NULL, NULL);
 473  E :    if (status != RPC_S_OK) {
 474  i :      LOG(ERROR) << "Failed to register RPC interface: "
 475    :                 << ::common::LogWe(status) << ".";
 476  i :      return false;
 477    :    }
 478    :  
 479    :    // Register the logger control interface.
 480  E :    VLOG(1) << "Registering the Logger Control interface.";
 481  E :    status = ::RpcServerRegisterIf(
 482    :        LoggerService_LoggerControl_v1_0_s_ifspec, NULL, NULL);
 483  E :    if (status != RPC_S_OK) {
 484  i :      LOG(ERROR) << "Failed to register RPC interface: "
 485    :                 << ::common::LogWe(status) << ".";
 486  i :      return false;
 487    :    }
 488    :  
 489  E :    OnInitialized();
 490    :  
 491  E :    return true;
 492  E :  }
 493    :  
 494  E :  bool AgentLogger::StartRpc() {
 495    :    // This method must be called by the owning thread, so no need to otherwise
 496    :    // synchronize the method invocation.
 497  E :    VLOG(1) << "Starting the RPC server.";
 498    :  
 499  E :    RPC_STATUS status = ::RpcServerListen(
 500    :        1,  // Minimum number of handler threads.
 501    :        RPC_C_LISTEN_MAX_CALLS_DEFAULT,
 502    :        TRUE);
 503    :  
 504  E :    if (status != RPC_S_OK) {
 505  i :      LOG(ERROR) << "Failed to run RPC server: " << ::common::LogWe(status)
 506    :                 << ".";
 507  i :      ignore_result(FinishRpc());
 508  i :      return false;
 509    :    }
 510    :  
 511    :    // Signal that the RPC is up and running.
 512  E :    DCHECK(!started_event_.IsValid());
 513  E :    std::wstring event_name;
 514  E :    GetSyzygyAgentLoggerEventName(instance_id(), &event_name);
 515  E :    started_event_.Set(::CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
 516  E :    if (!started_event_.IsValid()) {
 517  i :      DWORD error = ::GetLastError();
 518  i :      LOG(ERROR) << "Failed to create event: " << ::common::LogWe(error) << ".";
 519  i :      return false;
 520    :    }
 521  E :    BOOL success = ::SetEvent(started_event_.Get());
 522  E :    DCHECK(success);
 523    :  
 524    :    // Invoke the callback for the logger started event, giving it a chance to
 525    :    // abort the startup.
 526  E :    if (!OnStarted()) {
 527  i :      ignore_result(StopRpc());
 528  i :      ignore_result(FinishRpc());
 529  i :      return false;
 530    :    }
 531    :  
 532  E :    return true;
 533  E :  }
 534    :  
 535  E :  bool AgentLogger::StopRpc() {
 536    :    // This method may be called by any thread, but it does not inspect or modify
 537    :    // the internal state of the Logger; so, no synchronization is required.
 538  E :    VLOG(1) << "Requesting an asynchronous shutdown of the logging service.";
 539    :  
 540  E :    BOOL success = ::ResetEvent(started_event_.Get());
 541  E :    DCHECK(success);
 542    :  
 543  E :    RPC_STATUS status = ::RpcMgmtStopServerListening(NULL);
 544  E :    if (status != RPC_S_OK) {
 545  i :      LOG(ERROR) << "Failed to stop the RPC server: "
 546    :                  << ::common::LogWe(status) << ".";
 547  i :      return false;
 548    :    }
 549    :  
 550  E :    if (!OnInterrupted())
 551  i :      return false;
 552    :  
 553  E :    return true;
 554  E :  }
 555    :  
 556  E :  bool AgentLogger::FinishRpc() {
 557  E :    bool error = false;
 558  E :    RPC_STATUS status = RPC_S_OK;
 559    :  
 560    :    // Run the RPC server to completion. This is a blocking call which will only
 561    :    // terminate after someone calls StopRpc() on another thread.
 562  E :    status = RpcMgmtWaitServerListen();
 563  E :    if (status != RPC_S_OK) {
 564  i :      LOG(ERROR) << "Failed to wait for RPC server shutdown: "
 565    :                  << ::common::LogWe(status) << ".";
 566  i :      error = true;
 567    :    }
 568    :  
 569  E :    status = ::RpcServerUnregisterIf(
 570    :        LoggerService_Logger_v1_0_s_ifspec, NULL, FALSE);
 571  E :    if (status != RPC_S_OK) {
 572  i :      LOG(ERROR) << "Failed to unregister the AgentLogger RPC interface: "
 573    :                  << ::common::LogWe(status) << ".";
 574  i :      error = true;
 575    :    }
 576    :  
 577  E :    status = ::RpcServerUnregisterIf(
 578    :        LoggerService_LoggerControl_v1_0_s_ifspec, NULL, FALSE);
 579  E :    if (status != RPC_S_OK) {
 580  i :      LOG(ERROR) << "Failed to unregister AgentLogger Control RPC interface: "
 581    :                  << ::common::LogWe(status) << ".";
 582  i :      error = true;
 583    :    }
 584    :  
 585  E :    LOG(INFO) << "The logging service has stopped.";
 586  E :    if (!OnStopped())
 587  i :      error = true;
 588    :  
 589  E :    return !error;
 590  E :  }
 591    :  
 592    :  void AgentLogger::GetSyzygyAgentLoggerEventName(const base::StringPiece16& id,
 593  E :                                                  std::wstring* output) {
 594  E :    DCHECK(output != NULL);
 595  E :    const wchar_t* const kAgentLoggerSvcEvent = L"syzygy-agent-logger-svc-event";
 596    :  
 597  E :    output->assign(kAgentLoggerSvcEvent);
 598  E :    if (!id.empty()) {
 599  E :      output->append(1, '-');
 600  E :      output->append(id.begin(), id.end());
 601    :    }
 602  E :  }
 603    :  
 604    :  }  // namespace agent_logger
 605    :  }  // namespace trace

Coverage information generated Fri Jul 29 11:00:21 2016.