Coverage for /Syzygy/trace/parse/parse_engine.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.3%3784140.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    :  // Base class for common trace parsing infrastructure.
  16    :  #include "syzygy/trace/parse/parse_engine.h"
  17    :  
  18    :  #include <windows.h>  // NOLINT
  19    :  #include <wmistr.h>  // NOLINT
  20    :  #include <evntrace.h>
  21    :  
  22    :  #include "base/logging.h"
  23    :  #include "syzygy/common/buffer_parser.h"
  24    :  #include "syzygy/common/com_utils.h"
  25    :  #include "syzygy/trace/parse/parser.h"
  26    :  
  27    :  namespace trace {
  28    :  namespace parser {
  29    :  
  30    :  using ::common::BinaryBufferReader;
  31    :  
  32    :  ParseEngine::ParseEngine(const char* name, bool fail_on_module_conflict)
  33    :      : event_handler_(nullptr),
  34    :        error_occurred_(false),
  35  E :        fail_on_module_conflict_(fail_on_module_conflict) {
  36  E :    DCHECK(name != nullptr);
  37  E :    DCHECK(name[0] != '\0');
  38  E :    name_ = name;
  39  E :  }
  40    :  
  41  E :  ParseEngine::~ParseEngine() {
  42  E :  }
  43    :  
  44  E :  const char* ParseEngine::name() const {
  45  E :    return name_.c_str();
  46  E :  }
  47    :  
  48  E :  bool ParseEngine::error_occurred() const {
  49  E :    return error_occurred_;
  50  E :  }
  51    :  
  52  E :  void ParseEngine::set_error_occurred(bool value) {
  53  E :    error_occurred_ = value;
  54  E :  }
  55    :  
  56  E :  void ParseEngine::set_event_handler(ParseEventHandler* event_handler) {
  57  E :    DCHECK(event_handler_ == nullptr);
  58  E :    DCHECK(event_handler != nullptr);
  59  E :    event_handler_ = event_handler;
  60  E :  }
  61    :  
  62    :  const ModuleInformation* ParseEngine::GetModuleInformation(
  63  E :      uint32 process_id, AbsoluteAddress64 addr) const {
  64  E :    ProcessMap::const_iterator processes_it = processes_.find(process_id);
  65  E :    if (processes_it == processes_.end())
  66  E :      return nullptr;
  67    :  
  68  E :    const ModuleSpace& module_space = processes_it->second;
  69  E :    ModuleSpace::Range range(addr, 1);
  70    :    ModuleSpace::RangeMapConstIter module_it =
  71  E :        module_space.FindFirstIntersection(range);
  72  E :    if (module_it == module_space.end())
  73  E :      return nullptr;
  74    :  
  75  E :    return &module_it->second;
  76  E :  }
  77    :  
  78    :  bool ParseEngine::AddModuleInformation(DWORD process_id,
  79  E :                                         const ModuleInformation& module_info) {
  80    :    // Avoid doing needless work.
  81  E :    if (module_info.module_size == 0)
  82  i :      return true;
  83    :  
  84    :    // This happens in Windows XP ETW traces for some reason. They contain
  85    :    // conflicting information, so we ignore them.
  86  E :    if (module_info.path.empty())
  87  i :      return true;
  88    :  
  89  E :    ModuleSpace& module_space = processes_[process_id];
  90  E :    AbsoluteAddress64 addr(module_info.base_address.value());
  91  E :    ModuleSpace::Range range(addr, module_info.module_size);
  92    :  
  93  E :    AnnotatedModuleInformation new_module_info(module_info);
  94    :  
  95  E :    ModuleSpace::RangeMapIter iter;
  96  E :    if (module_space.FindOrInsert(range, new_module_info, &iter)) {
  97  E :      return true;
  98    :    }
  99    :  
 100    :    // Perhaps this is a case of conflicting paths for the same module. We often
 101    :    // get paths reported to us in \Device\HarddiskVolumeN\... notation, and
 102    :    // othertimes in C:\... notation. In this case we're happy if everything
 103    :    // matches except the path. For a little bit of extra sanity checking we
 104    :    // also check the basename of the paths.
 105    :    if (module_info.base_address == iter->second.base_address &&
 106    :        module_info.module_checksum == iter->second.module_checksum &&
 107    :        module_info.module_size == iter->second.module_size &&
 108    :        module_info.module_time_date_stamp ==
 109  E :            iter->second.module_time_date_stamp) {
 110  E :      base::FilePath path1(module_info.path);
 111  E :      base::FilePath path2(iter->second.path);
 112  E :      if (path1.BaseName() == path2.BaseName()) {
 113  E :        return true;
 114    :      }
 115  i :    }
 116    :  
 117    :    // Perhaps this is a case of process id reuse. In that case, we should have
 118    :    // previously seen a module unload event and marked the module information
 119    :    // as dirty.
 120  E :    while (iter->second.is_dirty) {
 121  E :      module_space.Remove(iter->first);
 122  E :      if (module_space.FindOrInsert(range, new_module_info, &iter)) {
 123  E :        return true;
 124    :      }
 125  i :    }
 126    :  
 127  E :    LOG(ERROR) << "Conflicting module info for pid=" << process_id << ": "
 128    :               << module_info.path
 129    :               << " (base=0x" << module_info.base_address
 130    :               << ", size=" << module_info.module_size << ") and "
 131    :               << iter->second.path
 132    :               << " (base=0x" << iter->second.base_address
 133    :               << ", size=" << iter->second.module_size << ").";
 134    :  
 135  E :    return fail_on_module_conflict_ ? false : true;
 136  E :  }
 137    :  
 138    :  bool ParseEngine::RemoveModuleInformation(
 139  E :      DWORD process_id, const ModuleInformation& module_info) {
 140    :    // Avoid doing needless work.
 141  E :    if (module_info.module_size == 0)
 142  i :      return true;
 143    :  
 144    :    // This happens in Windows XP traces for some reason. They contain conflicing
 145    :    // information, so we ignore them.
 146  E :    if (module_info.path.empty())
 147  i :      return true;
 148    :  
 149  E :    ModuleSpace& module_space = processes_[process_id];
 150  E :    AbsoluteAddress64 addr(module_info.base_address.value());
 151  E :    ModuleSpace::Range range(addr, module_info.module_size);
 152  E :    ModuleSpace::RangeMapIter it = module_space.FindFirstIntersection(range);
 153  E :    if (it == module_space.end()) {
 154    :      // We occasionally see this, as certain modules fire off multiple Unload
 155    :      // events, so we don't log an error. I'm looking at you, logman.exe.
 156  E :      return true;
 157    :    }
 158  E :    if (it->first != range) {
 159  i :      LOG(ERROR) << "Trying to remove module with mismatching range: "
 160    :                 << module_info.path
 161    :                 << " (base=0x" << module_info.base_address
 162    :                 << ", size=" << module_info.module_size << ").";
 163  i :      if (fail_on_module_conflict_)
 164  i :        return false;
 165    :    }
 166    :  
 167    :    // We only remove modules from a given process if a conflicting module is
 168    :    // loaded after the module has been marked as dirty. This is because (1) we
 169    :    // don't guarantee temporal order of all events in a process, so you
 170    :    // might parse a function event after seeing the module get unloaded
 171    :    // if the buffers are flushed in that order; and (2) because process ids may
 172    :    // be reused (but not concurrently) so we do want to drop stale module info
 173    :    // when the process has been replaced.
 174    :  
 175  E :    it->second.is_dirty = true;
 176    :  
 177  E :    return true;
 178  E :  }
 179    :  
 180  E :  bool ParseEngine::RemoveProcessInformation(DWORD process_id) {
 181  E :    ProcessMap::iterator proc_iter = processes_.find(process_id);
 182  E :    if (proc_iter == processes_.end()) {
 183  i :      LOG(ERROR) << "Unknown process id: " << process_id << ".";
 184  i :      return false;
 185    :    }
 186    :  
 187  E :    ModuleSpace& process_info = proc_iter->second;
 188    :  
 189  E :    ModuleSpace::iterator module_iter = process_info.begin();
 190  E :    for (; module_iter != process_info.end(); ++module_iter) {
 191  E :      module_iter->second.is_dirty = true;
 192  E :    }
 193    :  
 194  E :    return true;
 195  E :  }
 196    :  
 197  E :  bool ParseEngine::DispatchEvent(EVENT_TRACE* event) {
 198  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 199  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 200  E :    DCHECK(!error_occurred_);
 201    :  
 202  E :    if (kCallTraceEventClass != event->Header.Guid)
 203  E :      return false;
 204    :  
 205  E :    bool success = false;
 206  E :    TraceEventType type = static_cast<TraceEventType>(event->Header.Class.Type);
 207    :  
 208  E :    switch (type) {
 209    :      case TRACE_ENTER_EVENT:
 210    :      case TRACE_EXIT_EVENT:
 211  E :        success = DispatchEntryExitEvent(event, type);
 212  E :        break;
 213    :  
 214    :      case TRACE_BATCH_ENTER:
 215  E :        success = DispatchBatchEnterEvent(event);
 216  E :        break;
 217    :  
 218    :      case TRACE_PROCESS_ATTACH_EVENT:
 219    :      case TRACE_PROCESS_DETACH_EVENT:
 220    :      case TRACE_THREAD_ATTACH_EVENT:
 221    :      case TRACE_THREAD_DETACH_EVENT:
 222  E :        success = DispatchModuleEvent(event, type);
 223  E :        break;
 224    :  
 225    :      case TRACE_PROCESS_ENDED:
 226  E :        success = DispatchProcessEndedEvent(event);
 227  E :        break;
 228    :  
 229    :      case TRACE_MODULE_EVENT:
 230  i :        LOG(ERROR) << "Parsing for TRACE_MODULE_EVENT not yet implemented.";
 231  i :        break;
 232    :  
 233    :      case TRACE_BATCH_INVOCATION:
 234  E :        success = DispatchBatchInvocationEvent(event);
 235  E :        break;
 236    :  
 237    :      case TRACE_THREAD_NAME:
 238  E :        success = DispatchThreadNameEvent(event);
 239  E :        break;
 240    :  
 241    :      case TRACE_INDEXED_FREQUENCY:
 242  E :        success = DispatchIndexedFrequencyEvent(event);
 243  E :        break;
 244    :  
 245    :      case TRACE_DYNAMIC_SYMBOL:
 246  E :        success = DispatchDynamicSymbolEvent(event);
 247  E :        break;
 248    :  
 249    :      case TRACE_SAMPLE_DATA:
 250  E :        success = DispatchSampleDataEvent(event);
 251  E :        break;
 252    :  
 253    :      case TRACE_FUNCTION_NAME_TABLE_ENTRY:
 254  E :        success = DispatchFunctionNameTableEntryEvent(event);
 255  E :        break;
 256    :  
 257    :      case TRACE_STACK_TRACE:
 258  E :        success = DispatchStackTrace(event);
 259  E :        break;
 260    :  
 261    :      case TRACE_DETAILED_FUNCTION_CALL:
 262  E :        success = DispatchDetailedFunctionCall(event);
 263  E :        break;
 264    :  
 265    :      case TRACE_COMMENT:
 266  E :        success = DispatchComment(event);
 267  E :        break;
 268    :  
 269    :      case TRACE_PROCESS_HEAP:
 270  E :        success = DispatchProcessHeap(event);
 271  E :        break;
 272    :  
 273    :      default:
 274  E :        LOG(ERROR) << "Unknown event type encountered.";
 275    :        break;
 276    :    }
 277    :  
 278  E :    if (!success)
 279  E :      error_occurred_ = true;
 280    :  
 281  E :    return true;
 282  E :  }
 283    :  
 284    :  bool ParseEngine::DispatchEntryExitEvent(EVENT_TRACE* event,
 285  E :                                           TraceEventType type) {
 286  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 287  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 288  E :    DCHECK(!error_occurred_);
 289  E :    DCHECK(type == TRACE_ENTER_EVENT || type == TRACE_EXIT_EVENT);
 290    :  
 291  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 292  E :    const TraceEnterExitEventData* data = nullptr;
 293    :  
 294  E :    if (!reader.Read(sizeof(TraceEnterExitEventData), &data)) {
 295  E :      LOG(ERROR) << "Short entry exit event.";
 296  E :      return false;
 297    :    }
 298    :  
 299    :    base::Time time(base::Time::FromFileTime(
 300  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 301  E :    DWORD process_id = event->Header.ProcessId;
 302  E :    DWORD thread_id = event->Header.ThreadId;
 303    :  
 304  E :    switch (type) {
 305    :      case TRACE_ENTER_EVENT:
 306  E :        event_handler_->OnFunctionEntry(time, process_id, thread_id, data);
 307  E :        break;
 308    :  
 309    :      case TRACE_EXIT_EVENT:
 310  E :        event_handler_->OnFunctionExit(time, process_id, thread_id, data);
 311  E :        break;
 312    :  
 313    :      default:
 314  i :        NOTREACHED() << "Impossible event type.";
 315  i :        return false;
 316    :    }
 317    :  
 318  E :    return true;
 319  E :  }
 320    :  
 321  E :  bool ParseEngine::DispatchBatchEnterEvent(EVENT_TRACE* event) {
 322  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 323  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 324  E :    DCHECK(!error_occurred_);
 325    :  
 326  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 327  E :    const TraceBatchEnterData* data = nullptr;
 328  E :    size_t offset_to_calls = FIELD_OFFSET(TraceBatchEnterData, calls);
 329  E :    if (!reader.Read(offset_to_calls, &data)) {
 330  E :      LOG(ERROR) << "Short or empty batch event.";
 331  E :      return false;
 332    :    }
 333    :  
 334  E :    size_t bytes_needed = data->num_calls * sizeof(data->calls[0]);
 335  E :    if (!reader.Consume(bytes_needed)) {
 336  E :      LOG(ERROR) << "Short batch event data. Expected " << data->num_calls
 337    :                 << " entries (" << (offset_to_calls + bytes_needed)
 338    :                 << " bytes) but batch record was only " << event->MofLength
 339    :                 << " bytes.";
 340  E :      return false;
 341    :    }
 342    :  
 343    :    // Trim the batch entries if the last one is nullptr, indicating that the
 344    :    // reporting thread was interrupted mid-write.
 345    :    if (data->num_calls != 0 &&
 346  E :        data->calls[data->num_calls - 1].function == nullptr) {
 347    :      // Yuck! Cast away constness because the BinaryBufferReader only likes
 348    :      // to deal with const output pointers.
 349  E :      const_cast<TraceBatchEnterData*>(data)->num_calls -= 1;
 350    :    }
 351    :    DCHECK(data->num_calls == 0 ||
 352  E :           data->calls[data->num_calls - 1].function != nullptr);
 353    :  
 354    :    base::Time time(base::Time::FromFileTime(
 355  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 356  E :    DWORD process_id = event->Header.ProcessId;
 357  E :    DWORD thread_id = data->thread_id;
 358  E :    event_handler_->OnBatchFunctionEntry(time, process_id, thread_id, data);
 359  E :    return true;
 360  E :  }
 361    :  
 362  E :  bool ParseEngine::DispatchProcessEndedEvent(EVENT_TRACE* event) {
 363  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 364  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 365  E :    DCHECK(!error_occurred_);
 366    :  
 367    :    base::Time time(base::Time::FromFileTime(
 368  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 369    :  
 370  E :    event_handler_->OnProcessEnded(time, event->Header.ProcessId);
 371  E :    if (!RemoveProcessInformation(event->Header.ProcessId))
 372  i :      return false;
 373    :  
 374  E :    return true;
 375  E :  }
 376    :  
 377  E :  bool ParseEngine::DispatchBatchInvocationEvent(EVENT_TRACE* event) {
 378  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 379  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 380  E :    DCHECK(!error_occurred_);
 381    :  
 382  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 383  E :    if (event->MofLength % sizeof(InvocationInfo) != 0) {
 384  i :      LOG(ERROR) << "Invocation batch length off.";
 385  i :      return false;
 386    :    }
 387    :  
 388  E :    const TraceBatchInvocationInfo* data = nullptr;
 389  E :    if (!reader.Read(event->MofLength, &data)) {
 390  i :      LOG(ERROR) << "Short or empty batch event.";
 391  i :      return false;
 392    :    }
 393    :  
 394    :    // TODO(rogerm): Ensure this is robust in the presence of incomplete write.
 395  E :    size_t num_invocations = event->MofLength / sizeof(InvocationInfo);
 396    :    base::Time time(base::Time::FromFileTime(
 397  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 398  E :    DWORD process_id = event->Header.ProcessId;
 399  E :    DWORD thread_id = event->Header.ThreadId;
 400    :    event_handler_->OnInvocationBatch(time,
 401    :                                      process_id,
 402    :                                      thread_id,
 403    :                                      num_invocations,
 404  E :                                      data);
 405    :  
 406  E :    return true;
 407  E :  }
 408    :  
 409  E :  bool ParseEngine::DispatchThreadNameEvent(EVENT_TRACE* event) {
 410  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 411  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 412  E :    DCHECK(!error_occurred_);
 413    :  
 414  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 415  E :    const char* thread_name = nullptr;
 416  E :    size_t thread_name_len = 0;
 417  E :    if (!reader.ReadString(&thread_name, &thread_name_len)) {
 418  i :      LOG(ERROR) << "Unable to read string.";
 419  i :      return false;
 420    :    }
 421    :  
 422    :    base::Time time(base::Time::FromFileTime(
 423  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 424  E :    DWORD process_id = event->Header.ProcessId;
 425  E :    DWORD thread_id = event->Header.ThreadId;
 426    :    event_handler_->OnThreadName(time,
 427    :                                 process_id,
 428    :                                 thread_id,
 429  E :                                 base::StringPiece(thread_name, thread_name_len));
 430    :  
 431  E :    return true;
 432  E :  }
 433    :  
 434  E :  bool ParseEngine::DispatchIndexedFrequencyEvent(EVENT_TRACE* event) {
 435  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 436  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 437  E :    DCHECK(!error_occurred_);
 438    :  
 439  E :    if (event->MofLength < sizeof(TraceIndexedFrequencyData)) {
 440  E :      LOG(ERROR) << "Data too small for TraceIndexedFrequency struct.";
 441  E :      return false;
 442    :    }
 443    :  
 444  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 445  E :    const TraceIndexedFrequencyData* data = nullptr;
 446  E :    if (!reader.Read(&data)) {
 447  i :      LOG(ERROR) << "Short or empty coverage data event.";
 448  i :      return false;
 449    :    }
 450  E :    DCHECK(data != nullptr);
 451    :  
 452    :    // Calculate the expected size of the entire payload, headers included.
 453    :    size_t expected_length = data->frequency_size * data->num_entries +
 454  E :        sizeof(TraceIndexedFrequencyData) - 1;
 455  E :    if (event->MofLength < expected_length) {
 456  E :      LOG(ERROR) << "Payload smaller than size implied by "
 457    :                 << "TraceIndexedFrequencyData header.";
 458  E :      return false;
 459    :    }
 460    :  
 461    :    base::Time time(base::Time::FromFileTime(
 462  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 463  E :    DWORD process_id = event->Header.ProcessId;
 464  E :    DWORD thread_id = event->Header.ThreadId;
 465  E :    event_handler_->OnIndexedFrequency(time, process_id, thread_id, data);
 466    :  
 467  E :    return true;
 468  E :  }
 469    :  
 470  E :  bool ParseEngine::DispatchDynamicSymbolEvent(EVENT_TRACE* event) {
 471  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 472  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 473  E :    DCHECK(!error_occurred_);
 474    :  
 475  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 476  E :    const TraceDynamicSymbol* symbol = nullptr;
 477  E :    const char* symbol_name = nullptr;
 478  E :    size_t symbol_name_len = 0;
 479    :    if (!reader.Read(FIELD_OFFSET(TraceDynamicSymbol, symbol_name), &symbol) ||
 480  E :        !reader.ReadString(&symbol_name, &symbol_name_len)) {
 481  E :      LOG(ERROR) << "Short or empty coverage data event.";
 482  E :      return false;
 483    :    }
 484    :  
 485  E :    DWORD process_id = event->Header.ProcessId;
 486    :    event_handler_->OnDynamicSymbol(
 487    :        process_id, symbol->symbol_id,
 488  E :        base::StringPiece(symbol_name, symbol_name_len));
 489    :  
 490  E :    return true;
 491  E :  }
 492    :  
 493  E :  bool ParseEngine::DispatchSampleDataEvent(EVENT_TRACE* event) {
 494  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 495  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 496  E :    DCHECK(!error_occurred_);
 497    :  
 498  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 499  E :    const TraceSampleData* data = nullptr;
 500  E :    if (!reader.Read(&data)) {
 501  i :      LOG(ERROR) << "Short or empty TraceSampleData event.";
 502  i :      return false;
 503    :    }
 504  E :    DCHECK(data != nullptr);
 505    :  
 506    :    // Calculate the expected size of the entire payload, headers included.
 507    :    size_t expected_length = FIELD_OFFSET(TraceSampleData, buckets) +
 508  E :        sizeof(data->buckets[0]) * data->bucket_count;
 509  E :    if (event->MofLength < expected_length) {
 510  E :      LOG(ERROR) << "Payload smaller than size implied by TraceSampleData "
 511    :                 << "header.";
 512  E :      return false;
 513    :    }
 514    :  
 515    :    base::Time time(base::Time::FromFileTime(
 516  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 517  E :    DWORD process_id = event->Header.ProcessId;
 518  E :    event_handler_->OnSampleData(time, process_id, data);
 519    :  
 520  E :    return true;
 521  E :  }
 522    :  
 523  E :  bool ParseEngine::DispatchFunctionNameTableEntryEvent(EVENT_TRACE* event) {
 524  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 525  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 526  E :    DCHECK(!error_occurred_);
 527    :  
 528  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 529  E :    const TraceFunctionNameTableEntry* data = nullptr;
 530  E :    if (!reader.Read(&data)) {
 531  i :      LOG(ERROR) << "Short or empty TraceFunctionNameTableEntry event.";
 532  i :      return false;
 533    :    }
 534  E :    DCHECK(data != nullptr);
 535    :  
 536    :    // Calculate the expected size of the payload and ensure there's
 537    :    // enough data.
 538    :    size_t expected_length = FIELD_OFFSET(TraceFunctionNameTableEntry, name) +
 539  E :        data->name_length;
 540  E :    if (event->MofLength < expected_length) {
 541  E :      LOG(ERROR) << "Payload smaller than size implied by "
 542    :                 << "TraceFunctionNameTableEntry header.";
 543  E :      return false;
 544    :    }
 545    :  
 546    :    base::Time time(base::Time::FromFileTime(
 547  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 548  E :    DWORD process_id = event->Header.ProcessId;
 549  E :    event_handler_->OnFunctionNameTableEntry(time, process_id, data);
 550    :  
 551  E :    return true;
 552  E :  }
 553    :  
 554  E :  bool ParseEngine::DispatchStackTrace(EVENT_TRACE* event) {
 555  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 556  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 557  E :    DCHECK(!error_occurred_);
 558    :  
 559  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 560  E :    const TraceStackTrace* data = nullptr;
 561  E :    if (!reader.Read(&data)) {
 562  i :      LOG(ERROR) << "Short or empty TraceStackTrace event.";
 563  i :      return false;
 564    :    }
 565  E :    DCHECK(data != nullptr);
 566    :  
 567    :    // Calculate the expected size of the payload and ensure there's
 568    :    // enough data.
 569    :    size_t expected_length = FIELD_OFFSET(TraceStackTrace, frames) +
 570  E :        data->num_frames * sizeof(void*);
 571  E :    if (event->MofLength < expected_length) {
 572  E :      LOG(ERROR) << "Payload smaller than size implied by "
 573    :                 << "TraceStackTrace header.";
 574  E :      return false;
 575    :    }
 576    :  
 577    :    base::Time time(base::Time::FromFileTime(
 578  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 579  E :    DWORD process_id = event->Header.ProcessId;
 580  E :    event_handler_->OnStackTrace(time, process_id, data);
 581    :  
 582  E :    return true;
 583  E :  }
 584    :  
 585  E :  bool ParseEngine::DispatchDetailedFunctionCall(EVENT_TRACE* event) {
 586  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 587  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 588  E :    DCHECK(!error_occurred_);
 589    :  
 590  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 591  E :    const TraceDetailedFunctionCall* data = nullptr;
 592  E :    if (!reader.Read(&data)) {
 593  i :      LOG(ERROR) << "Short or empty TraceDetailedFunctionCall event.";
 594  i :      return false;
 595    :    }
 596  E :    DCHECK(data != nullptr);
 597    :  
 598    :    // Calculate the expected size of the payload and ensure there's
 599    :    // enough data.
 600    :    size_t expected_length =
 601    :        FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
 602  E :        data->argument_data_size;
 603  E :    if (event->MofLength < expected_length) {
 604  E :      LOG(ERROR) << "Payload smaller than size implied by "
 605    :                 << "TraceDetailedFunctionCall header.";
 606  E :      return false;
 607    :    }
 608    :  
 609    :    base::Time time(base::Time::FromFileTime(
 610  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 611  E :    DWORD process_id = event->Header.ProcessId;
 612  E :    DWORD thread_id = event->Header.ThreadId;
 613  E :    event_handler_->OnDetailedFunctionCall(time, process_id, thread_id, data);
 614    :  
 615  E :    return true;
 616  E :  }
 617    :  
 618  E :  bool ParseEngine::DispatchComment(EVENT_TRACE* event) {
 619  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 620  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 621  E :    DCHECK(!error_occurred_);
 622    :  
 623  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 624  E :    const TraceComment* data = nullptr;
 625  E :    if (!reader.Read(&data)) {
 626  i :      LOG(ERROR) << "Short or empty TraceComment event.";
 627  i :      return false;
 628    :    }
 629  E :    DCHECK(data != nullptr);
 630    :  
 631    :    // Calculate the expected size of the payload and ensure there's
 632    :    // enough data.
 633    :    size_t expected_length =
 634    :        FIELD_OFFSET(TraceComment, comment) +
 635  E :        data->comment_size;
 636  E :    if (event->MofLength < expected_length) {
 637  E :      LOG(ERROR) << "Payload smaller than size implied by "
 638    :                 << "TraceComment header.";
 639  E :      return false;
 640    :    }
 641    :  
 642    :    base::Time time(base::Time::FromFileTime(
 643  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 644  E :    DWORD process_id = event->Header.ProcessId;
 645  E :    event_handler_->OnComment(time, process_id, data);
 646    :  
 647  E :    return true;
 648  E :  }
 649    :  
 650  E :  bool ParseEngine::DispatchProcessHeap(EVENT_TRACE* event) {
 651  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 652  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 653  E :    DCHECK(!error_occurred_);
 654    :  
 655  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 656  E :    const TraceProcessHeap* data = nullptr;
 657  E :    if (!reader.Read(&data)) {
 658  E :      LOG(ERROR) << "Short or empty TraceProcessHeap event.";
 659  E :      return false;
 660    :    }
 661  E :    DCHECK(data != nullptr);
 662    :  
 663    :    base::Time time(base::Time::FromFileTime(
 664  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 665  E :    DWORD process_id = event->Header.ProcessId;
 666  E :    event_handler_->OnProcessHeap(time, process_id, data);
 667    :  
 668  E :    return true;
 669  E :  }
 670    :  
 671    :  namespace {
 672    :  
 673    :  void ModuleTraceDataToModuleInformation(
 674    :      const TraceModuleData& module_data,
 675  E :      ModuleInformation* module_info) {
 676  E :    DCHECK_NE(static_cast<ModuleInformation*>(nullptr), module_info);
 677    :    module_info->base_address.set_value(
 678  E :        reinterpret_cast<uint32>(module_data.module_base_addr));
 679  E :    module_info->module_size = module_data.module_base_size;
 680  E :    module_info->path = module_data.module_name;
 681  E :    module_info->module_checksum = module_data.module_checksum;
 682  E :    module_info->module_time_date_stamp = module_data.module_time_date_stamp;
 683  E :  }
 684    :  
 685    :  }  // namespace
 686    :  
 687    :  bool ParseEngine::DispatchModuleEvent(EVENT_TRACE* event,
 688  E :                                        TraceEventType type) {
 689  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 690  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 691  E :    DCHECK(!error_occurred_);
 692    :    DCHECK(type == TRACE_PROCESS_ATTACH_EVENT ||
 693    :           type == TRACE_PROCESS_DETACH_EVENT ||
 694    :           type == TRACE_THREAD_ATTACH_EVENT ||
 695  E :           type == TRACE_THREAD_DETACH_EVENT);
 696    :  
 697  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 698  E :    const TraceModuleData* data = nullptr;
 699  E :    if (!reader.Read(&data)) {
 700  E :      LOG(ERROR) << "Short or empty module event.";
 701  E :      return false;
 702    :    }
 703    :  
 704  E :    if (data->module_base_addr == nullptr) {
 705  E :      LOG(INFO) << "Encountered incompletely written module event record.";
 706  E :      return true;
 707    :    }
 708    :  
 709    :    base::Time time(base::Time::FromFileTime(
 710  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 711  E :    DWORD process_id = event->Header.ProcessId;
 712  E :    DWORD thread_id = event->Header.ThreadId;
 713    :  
 714  E :    switch (type) {
 715    :      case TRACE_PROCESS_ATTACH_EVENT: {
 716  E :        ModuleInformation module_info;
 717  E :        ModuleTraceDataToModuleInformation(*data, &module_info);
 718  E :        AddModuleInformation(process_id, module_info);
 719  E :        event_handler_->OnProcessAttach(time, process_id, thread_id, data);
 720  E :        break;
 721    :      }
 722    :  
 723    :      case TRACE_PROCESS_DETACH_EVENT: {
 724  E :        event_handler_->OnProcessDetach(time, process_id, thread_id, data);
 725  E :        ModuleInformation module_info;
 726  E :        ModuleTraceDataToModuleInformation(*data, &module_info);
 727  E :        RemoveModuleInformation(process_id, module_info);
 728  E :        break;
 729    :      }
 730    :  
 731    :      case TRACE_THREAD_ATTACH_EVENT: {
 732  E :        event_handler_->OnThreadAttach(time, process_id, thread_id, data);
 733  E :        break;
 734    :      }
 735    :  
 736    :      case TRACE_THREAD_DETACH_EVENT: {
 737  E :        event_handler_->OnThreadDetach(time, process_id, thread_id, data);
 738  E :        break;
 739    :      }
 740    :  
 741    :      default: {
 742  i :        LOG(ERROR) << "Unexpected module event type " << type << ".";
 743  i :        return false;
 744    :      }
 745    :    }
 746    :  
 747  E :    return true;
 748  E :  }
 749    :  
 750    :  }  // namespace parser
 751    :  }  // namespace trace

Coverage information generated Thu Jan 14 17:40:38 2016.