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

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

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