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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
91.0%3623980.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_(NULL),
  34    :        error_occurred_(false),
  35  E :        fail_on_module_conflict_(fail_on_module_conflict) {
  36  E :    DCHECK(name != NULL);
  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_ == NULL);
  58  E :    DCHECK(event_handler != NULL);
  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 NULL;
  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 NULL;
  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    :      default:
 270  E :        LOG(ERROR) << "Unknown event type encountered.";
 271    :        break;
 272    :    }
 273    :  
 274  E :    if (!success) {
 275  E :      error_occurred_ = true;
 276    :    }
 277    :  
 278  E :    return true;
 279  E :  }
 280    :  
 281    :  bool ParseEngine::DispatchEntryExitEvent(EVENT_TRACE* event,
 282  E :                                           TraceEventType type) {
 283  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 284  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 285  E :    DCHECK(!error_occurred_);
 286  E :    DCHECK(type == TRACE_ENTER_EVENT || type == TRACE_EXIT_EVENT);
 287    :  
 288  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 289  E :    const TraceEnterExitEventData* data = NULL;
 290    :  
 291  E :    if (!reader.Read(sizeof(TraceEnterExitEventData), &data)) {
 292  E :      LOG(ERROR) << "Short entry exit event.";
 293  E :      return false;
 294    :    }
 295    :  
 296    :    base::Time time(base::Time::FromFileTime(
 297  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 298  E :    DWORD process_id = event->Header.ProcessId;
 299  E :    DWORD thread_id = event->Header.ThreadId;
 300    :  
 301  E :    switch (type) {
 302    :      case TRACE_ENTER_EVENT:
 303  E :        event_handler_->OnFunctionEntry(time, process_id, thread_id, data);
 304  E :        break;
 305    :  
 306    :      case TRACE_EXIT_EVENT:
 307  E :        event_handler_->OnFunctionExit(time, process_id, thread_id, data);
 308  E :        break;
 309    :  
 310    :      default:
 311  i :        NOTREACHED() << "Impossible event type.";
 312  i :        return false;
 313    :    }
 314    :  
 315  E :    return true;
 316  E :  }
 317    :  
 318  E :  bool ParseEngine::DispatchBatchEnterEvent(EVENT_TRACE* event) {
 319  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 320  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 321  E :    DCHECK(!error_occurred_);
 322    :  
 323  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 324  E :    const TraceBatchEnterData* data = NULL;
 325  E :    size_t offset_to_calls = FIELD_OFFSET(TraceBatchEnterData, calls);
 326  E :    if (!reader.Read(offset_to_calls, &data)) {
 327  E :      LOG(ERROR) << "Short or empty batch event.";
 328  E :      return false;
 329    :    }
 330    :  
 331  E :    size_t bytes_needed = data->num_calls * sizeof(data->calls[0]);
 332  E :    if (!reader.Consume(bytes_needed)) {
 333  E :      LOG(ERROR) << "Short batch event data. Expected " << data->num_calls
 334    :                 << " entries (" << (offset_to_calls + bytes_needed)
 335    :                 << " bytes) but batch record was only " << event->MofLength
 336    :                 << " bytes.";
 337  E :      return false;
 338    :    }
 339    :  
 340    :    // Trim the batch entries if the last one is NULL, indicating that the
 341    :    // reporting thread was interrupted mid-write.
 342    :    if (data->num_calls != 0 &&
 343  E :        data->calls[data->num_calls - 1].function == NULL) {
 344    :      // Yuck! Cast away constness because the BinaryBufferReader only likes
 345    :      // to deal with const output pointers.
 346  E :      const_cast<TraceBatchEnterData*>(data)->num_calls -= 1;
 347    :    }
 348    :    DCHECK(data->num_calls == 0 ||
 349  E :           data->calls[data->num_calls - 1].function != NULL);
 350    :  
 351    :    base::Time time(base::Time::FromFileTime(
 352  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 353  E :    DWORD process_id = event->Header.ProcessId;
 354  E :    DWORD thread_id = data->thread_id;
 355  E :    event_handler_->OnBatchFunctionEntry(time, process_id, thread_id, data);
 356  E :    return true;
 357  E :  }
 358    :  
 359  E :  bool ParseEngine::DispatchProcessEndedEvent(EVENT_TRACE* event) {
 360  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 361  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 362  E :    DCHECK(!error_occurred_);
 363    :  
 364    :    base::Time time(base::Time::FromFileTime(
 365  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 366    :  
 367  E :    event_handler_->OnProcessEnded(time, event->Header.ProcessId);
 368  E :    if (!RemoveProcessInformation(event->Header.ProcessId))
 369  i :      return false;
 370    :  
 371  E :    return true;
 372  E :  }
 373    :  
 374  E :  bool ParseEngine::DispatchBatchInvocationEvent(EVENT_TRACE* event) {
 375  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 376  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 377  E :    DCHECK(!error_occurred_);
 378    :  
 379  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 380  E :    if (event->MofLength % sizeof(InvocationInfo) != 0) {
 381  i :      LOG(ERROR) << "Invocation batch length off.";
 382  i :      return false;
 383    :    }
 384    :  
 385  E :    const TraceBatchInvocationInfo* data = NULL;
 386  E :    if (!reader.Read(event->MofLength, &data)) {
 387  i :      LOG(ERROR) << "Short or empty batch event.";
 388  i :      return false;
 389    :    }
 390    :  
 391    :    // TODO(rogerm): Ensure this is robust in the presence of incomplete write.
 392  E :    size_t num_invocations = event->MofLength / sizeof(InvocationInfo);
 393    :    base::Time time(base::Time::FromFileTime(
 394  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 395  E :    DWORD process_id = event->Header.ProcessId;
 396  E :    DWORD thread_id = event->Header.ThreadId;
 397    :    event_handler_->OnInvocationBatch(time,
 398    :                                      process_id,
 399    :                                      thread_id,
 400    :                                      num_invocations,
 401  E :                                      data);
 402    :  
 403  E :    return true;
 404  E :  }
 405    :  
 406  E :  bool ParseEngine::DispatchThreadNameEvent(EVENT_TRACE* event) {
 407  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 408  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 409  E :    DCHECK(!error_occurred_);
 410    :  
 411  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 412  E :    const char* thread_name = NULL;
 413  E :    size_t thread_name_len = 0;
 414  E :    if (!reader.ReadString(&thread_name, &thread_name_len)) {
 415  i :      LOG(ERROR) << "Unable to read string.";
 416  i :      return false;
 417    :    }
 418    :  
 419    :    base::Time time(base::Time::FromFileTime(
 420  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 421  E :    DWORD process_id = event->Header.ProcessId;
 422  E :    DWORD thread_id = event->Header.ThreadId;
 423    :    event_handler_->OnThreadName(time,
 424    :                                 process_id,
 425    :                                 thread_id,
 426  E :                                 base::StringPiece(thread_name, thread_name_len));
 427    :  
 428  E :    return true;
 429  E :  }
 430    :  
 431  E :  bool ParseEngine::DispatchIndexedFrequencyEvent(EVENT_TRACE* event) {
 432  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 433  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 434  E :    DCHECK(!error_occurred_);
 435    :  
 436  E :    if (event->MofLength < sizeof(TraceIndexedFrequencyData)) {
 437  E :      LOG(ERROR) << "Data too small for TraceIndexedFrequency struct.";
 438  E :      return false;
 439    :    }
 440    :  
 441  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 442  E :    const TraceIndexedFrequencyData* data = NULL;
 443  E :    if (!reader.Read(&data)) {
 444  i :      LOG(ERROR) << "Short or empty coverage data event.";
 445  i :      return false;
 446    :    }
 447  E :    DCHECK(data != NULL);
 448    :  
 449    :    // Calculate the expected size of the entire payload, headers included.
 450    :    size_t expected_length = data->frequency_size * data->num_entries +
 451  E :        sizeof(TraceIndexedFrequencyData) - 1;
 452  E :    if (event->MofLength < expected_length) {
 453  E :      LOG(ERROR) << "Payload smaller than size implied by "
 454    :                 << "TraceIndexedFrequencyData header.";
 455  E :      return false;
 456    :    }
 457    :  
 458    :    base::Time time(base::Time::FromFileTime(
 459  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 460  E :    DWORD process_id = event->Header.ProcessId;
 461  E :    DWORD thread_id = event->Header.ThreadId;
 462  E :    event_handler_->OnIndexedFrequency(time, process_id, thread_id, data);
 463    :  
 464  E :    return true;
 465  E :  }
 466    :  
 467  E :  bool ParseEngine::DispatchDynamicSymbolEvent(EVENT_TRACE* event) {
 468  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 469  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 470  E :    DCHECK(!error_occurred_);
 471    :  
 472  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 473  E :    const TraceDynamicSymbol* symbol = NULL;
 474  E :    const char* symbol_name = NULL;
 475  E :    size_t symbol_name_len = 0;
 476    :    if (!reader.Read(FIELD_OFFSET(TraceDynamicSymbol, symbol_name), &symbol) ||
 477  E :        !reader.ReadString(&symbol_name, &symbol_name_len)) {
 478  E :      LOG(ERROR) << "Short or empty coverage data event.";
 479  E :      return false;
 480    :    }
 481    :  
 482  E :    DWORD process_id = event->Header.ProcessId;
 483    :    event_handler_->OnDynamicSymbol(
 484    :        process_id, symbol->symbol_id,
 485  E :        base::StringPiece(symbol_name, symbol_name_len));
 486    :  
 487  E :    return true;
 488  E :  }
 489    :  
 490  E :  bool ParseEngine::DispatchSampleDataEvent(EVENT_TRACE* event) {
 491  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 492  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 493  E :    DCHECK(!error_occurred_);
 494    :  
 495  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 496  E :    const TraceSampleData* data = NULL;
 497  E :    if (!reader.Read(&data)) {
 498  i :      LOG(ERROR) << "Short or empty TraceSampleData event.";
 499  i :      return false;
 500    :    }
 501  E :    DCHECK(data != NULL);
 502    :  
 503    :    // Calculate the expected size of the entire payload, headers included.
 504    :    size_t expected_length = FIELD_OFFSET(TraceSampleData, buckets) +
 505  E :        sizeof(data->buckets[0]) * data->bucket_count;
 506  E :    if (event->MofLength < expected_length) {
 507  E :      LOG(ERROR) << "Payload smaller than size implied by TraceSampleData "
 508    :                 << "header.";
 509  E :      return false;
 510    :    }
 511    :  
 512    :    base::Time time(base::Time::FromFileTime(
 513  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 514  E :    DWORD process_id = event->Header.ProcessId;
 515  E :    event_handler_->OnSampleData(time, process_id, data);
 516    :  
 517  E :    return true;
 518  E :  }
 519    :  
 520  E :  bool ParseEngine::DispatchFunctionNameTableEntryEvent(EVENT_TRACE* event) {
 521  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 522  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 523  E :    DCHECK(!error_occurred_);
 524    :  
 525  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 526  E :    const TraceFunctionNameTableEntry* data = NULL;
 527  E :    if (!reader.Read(&data)) {
 528  i :      LOG(ERROR) << "Short or empty TraceFunctionNameTableEntry event.";
 529  i :      return false;
 530    :    }
 531  E :    DCHECK(data != NULL);
 532    :  
 533    :    // Calculate the expected size of the payload and ensure there's
 534    :    // enough data.
 535    :    size_t expected_length = FIELD_OFFSET(TraceFunctionNameTableEntry, name) +
 536  E :        data->name_length;
 537  E :    if (event->MofLength < expected_length) {
 538  E :      LOG(ERROR) << "Payload smaller than size implied by "
 539    :                 << "TraceFunctionNameTableEntry header.";
 540  E :      return false;
 541    :    }
 542    :  
 543    :    base::Time time(base::Time::FromFileTime(
 544  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 545  E :    DWORD process_id = event->Header.ProcessId;
 546  E :    event_handler_->OnFunctionNameTableEntry(time, process_id, data);
 547    :  
 548  E :    return true;
 549  E :  }
 550    :  
 551  E :  bool ParseEngine::DispatchStackTrace(EVENT_TRACE* event) {
 552  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 553  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 554  E :    DCHECK(!error_occurred_);
 555    :  
 556  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 557  E :    const TraceStackTrace* data = NULL;
 558  E :    if (!reader.Read(&data)) {
 559  i :      LOG(ERROR) << "Short or empty TraceStackTrace event.";
 560  i :      return false;
 561    :    }
 562  E :    DCHECK(data != NULL);
 563    :  
 564    :    // Calculate the expected size of the payload and ensure there's
 565    :    // enough data.
 566    :    size_t expected_length = FIELD_OFFSET(TraceStackTrace, frames) +
 567  E :        data->num_frames * sizeof(void*);
 568  E :    if (event->MofLength < expected_length) {
 569  E :      LOG(ERROR) << "Payload smaller than size implied by "
 570    :                 << "TraceStackTrace header.";
 571  E :      return false;
 572    :    }
 573    :  
 574    :    base::Time time(base::Time::FromFileTime(
 575  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 576  E :    DWORD process_id = event->Header.ProcessId;
 577  E :    event_handler_->OnStackTrace(time, process_id, data);
 578    :  
 579  E :    return true;
 580  E :  }
 581    :  
 582  E :  bool ParseEngine::DispatchDetailedFunctionCall(EVENT_TRACE* event) {
 583  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 584  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 585  E :    DCHECK(!error_occurred_);
 586    :  
 587  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 588  E :    const TraceDetailedFunctionCall* data = NULL;
 589  E :    if (!reader.Read(&data)) {
 590  i :      LOG(ERROR) << "Short or empty TraceDetailedFunctionCall event.";
 591  i :      return false;
 592    :    }
 593  E :    DCHECK(data != NULL);
 594    :  
 595    :    // Calculate the expected size of the payload and ensure there's
 596    :    // enough data.
 597    :    size_t expected_length =
 598    :        FIELD_OFFSET(TraceDetailedFunctionCall, argument_data) +
 599  E :        data->argument_data_size;
 600  E :    if (event->MofLength < expected_length) {
 601  E :      LOG(ERROR) << "Payload smaller than size implied by "
 602    :                 << "TraceDetailedFunctionCall header.";
 603  E :      return false;
 604    :    }
 605    :  
 606    :    base::Time time(base::Time::FromFileTime(
 607  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 608  E :    DWORD process_id = event->Header.ProcessId;
 609  E :    DWORD thread_id = event->Header.ThreadId;
 610  E :    event_handler_->OnDetailedFunctionCall(time, process_id, thread_id, data);
 611    :  
 612  E :    return true;
 613  E :  }
 614    :  
 615  E :  bool ParseEngine::DispatchComment(EVENT_TRACE* event) {
 616  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 617  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 618  E :    DCHECK(!error_occurred_);
 619    :  
 620  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 621  E :    const TraceComment* data = NULL;
 622  E :    if (!reader.Read(&data)) {
 623  i :      LOG(ERROR) << "Short or empty TraceComment event.";
 624  i :      return false;
 625    :    }
 626  E :    DCHECK(data != NULL);
 627    :  
 628    :    // Calculate the expected size of the payload and ensure there's
 629    :    // enough data.
 630    :    size_t expected_length =
 631    :        FIELD_OFFSET(TraceComment, comment) +
 632  E :        data->comment_size;
 633  E :    if (event->MofLength < expected_length) {
 634  E :      LOG(ERROR) << "Payload smaller than size implied by "
 635    :                 << "TraceComment header.";
 636  E :      return false;
 637    :    }
 638    :  
 639    :    base::Time time(base::Time::FromFileTime(
 640  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 641  E :    DWORD process_id = event->Header.ProcessId;
 642  E :    DWORD thread_id = event->Header.ThreadId;
 643  E :    event_handler_->OnComment(time, process_id, data);
 644    :  
 645  E :    return true;
 646  E :  }
 647    :  
 648    :  namespace {
 649    :  
 650    :  void ModuleTraceDataToModuleInformation(
 651    :      const TraceModuleData& module_data,
 652  E :      ModuleInformation* module_info) {
 653  E :    DCHECK_NE(reinterpret_cast<ModuleInformation*>(NULL), module_info);
 654    :    module_info->base_address.set_value(
 655  E :        reinterpret_cast<uint32>(module_data.module_base_addr));
 656  E :    module_info->module_size = module_data.module_base_size;
 657  E :    module_info->path = module_data.module_name;
 658  E :    module_info->module_checksum = module_data.module_checksum;
 659  E :    module_info->module_time_date_stamp = module_data.module_time_date_stamp;
 660  E :  }
 661    :  
 662    :  }  // namespace
 663    :  
 664    :  bool ParseEngine::DispatchModuleEvent(EVENT_TRACE* event,
 665  E :                                        TraceEventType type) {
 666  E :    DCHECK_NE(static_cast<EVENT_TRACE*>(nullptr), event);
 667  E :    DCHECK_NE(static_cast<ParseEventHandler*>(nullptr), event_handler_);
 668  E :    DCHECK(!error_occurred_);
 669    :    DCHECK(type == TRACE_PROCESS_ATTACH_EVENT ||
 670    :           type == TRACE_PROCESS_DETACH_EVENT ||
 671    :           type == TRACE_THREAD_ATTACH_EVENT ||
 672  E :           type == TRACE_THREAD_DETACH_EVENT);
 673    :  
 674  E :    BinaryBufferReader reader(event->MofData, event->MofLength);
 675  E :    const TraceModuleData* data = NULL;
 676  E :    if (!reader.Read(&data)) {
 677  E :      LOG(ERROR) << "Short or empty module event.";
 678  E :      return false;
 679    :    }
 680    :  
 681  E :    if (data->module_base_addr == NULL) {
 682  E :      LOG(INFO) << "Encountered incompletely written module event record.";
 683  E :      return true;
 684    :    }
 685    :  
 686    :    base::Time time(base::Time::FromFileTime(
 687  E :        reinterpret_cast<FILETIME&>(event->Header.TimeStamp)));
 688  E :    DWORD process_id = event->Header.ProcessId;
 689  E :    DWORD thread_id = event->Header.ThreadId;
 690    :  
 691  E :    switch (type) {
 692    :      case TRACE_PROCESS_ATTACH_EVENT: {
 693  E :        ModuleInformation module_info;
 694  E :        ModuleTraceDataToModuleInformation(*data, &module_info);
 695  E :        AddModuleInformation(process_id, module_info);
 696  E :        event_handler_->OnProcessAttach(time, process_id, thread_id, data);
 697  E :        break;
 698    :      }
 699    :  
 700    :      case TRACE_PROCESS_DETACH_EVENT: {
 701  E :        event_handler_->OnProcessDetach(time, process_id, thread_id, data);
 702  E :        ModuleInformation module_info;
 703  E :        ModuleTraceDataToModuleInformation(*data, &module_info);
 704  E :        RemoveModuleInformation(process_id, module_info);
 705  E :        break;
 706    :      }
 707    :  
 708    :      case TRACE_THREAD_ATTACH_EVENT: {
 709  E :        event_handler_->OnThreadAttach(time, process_id, thread_id, data);
 710  E :        break;
 711    :      }
 712    :  
 713    :      case TRACE_THREAD_DETACH_EVENT: {
 714  E :        event_handler_->OnThreadDetach(time, process_id, thread_id, data);
 715  E :        break;
 716    :      }
 717    :  
 718    :      default: {
 719  i :        LOG(ERROR) << "Unexpected module event type " << type << ".";
 720  i :        return false;
 721    :      }
 722    :    }
 723    :  
 724  E :    return true;
 725  E :  }
 726    :  
 727    :  }  // namespace parser
 728    :  }  // namespace trace

Coverage information generated Thu Mar 26 16:15:41 2015.