Coverage for /Syzygy/pe/dia_util.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
79.7%1922410.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    :  #include "syzygy/pe/dia_util.h"
  16    :  
  17    :  #include <diacreate.h>
  18    :  
  19    :  #include "base/logging.h"
  20    :  #include "base/win/scoped_bstr.h"
  21    :  #include "base/win/scoped_comptr.h"
  22    :  #include "syzygy/common/com_utils.h"
  23    :  
  24    :  namespace pe {
  25    :  
  26    :  using base::win::ScopedBstr;
  27    :  using base::win::ScopedComPtr;
  28    :  
  29    :  #if _MSC_VER == 1800  // MSVS 2013.
  30    :  const wchar_t kDiaDllName[] = L"msdia120.dll";
  31    :  #elif _MSC_VER == 1900  // MSVS 2015.
  32    :  const wchar_t kDiaDllName[] = L"msdia140.dll";
  33    :  #endif
  34    :  
  35    :  const wchar_t kFixupDiaDebugStreamName[] = L"FIXUP";
  36    :  const wchar_t kOmapToDiaDebugStreamName[] = L"OMAPTO";
  37    :  const wchar_t kOmapFromDiaDebugStreamName[] = L"OMAPFROM";
  38    :  
  39    :  namespace internal {
  40    :  
  41    :  bool CreateDiaObject(void** created_object, const CLSID& class_id,
  42  E :                       const IID& interface_identifier) {
  43  E :    DCHECK_NE(static_cast<void**>(nullptr), created_object);
  44    :  
  45  E :    *created_object = nullptr;
  46    :  
  47  E :    base::win::ScopedComPtr<IUnknown> dia_source;
  48    :  
  49  E :    HRESULT hr1 = NoRegCoCreate(kDiaDllName,
  50    :                                class_id,
  51    :                                interface_identifier,
  52    :                                reinterpret_cast<void**>(&dia_source));
  53  E :    if (SUCCEEDED(hr1)) {
  54  E :      *created_object = dia_source.Detach();
  55  E :      return true;
  56    :    }
  57    :  
  58  i :    HRESULT hr2 = dia_source.CreateInstance(CLSID_DiaSource);
  59  i :    if (SUCCEEDED(hr2)) {
  60  i :      *created_object = dia_source.Detach();
  61  i :      return true;
  62    :    }
  63    :  
  64  i :    LOG(ERROR) << "Failed to create Dia object.";
  65  i :    LOG(ERROR) << "  NoRegCoCreate failed with: " << common::LogHr(hr1);
  66  i :    LOG(ERROR) << "  CreateInstance failed with: " << common::LogHr(hr2);
  67    :  
  68  i :    return false;
  69  E :  }
  70    :  
  71    :  }  // namespace internal
  72    :  
  73  E :  bool CreateDiaSource(IDiaDataSource** created_source) {
  74  E :    return CreateDiaObject(created_source, CLSID_DiaSource);
  75  E :  }
  76    :  
  77    :  bool CreateDiaSession(const base::FilePath& file,
  78    :                        IDiaDataSource* dia_source,
  79  E :                        IDiaSession** dia_session) {
  80  E :    DCHECK(dia_source != NULL);
  81  E :    DCHECK(dia_session != NULL);
  82    :  
  83  E :    *dia_session = NULL;
  84    :  
  85  E :    HRESULT hr = E_FAIL;
  86    :  
  87  E :    if (file.Extension() == L".pdb") {
  88  E :      hr = dia_source->loadDataFromPdb(file.value().c_str());
  89  E :    } else {
  90  E :      hr = dia_source->loadDataForExe(file.value().c_str(), NULL, NULL);
  91    :    }
  92    :  
  93  E :    if (FAILED(hr)) {
  94  i :      LOG(ERROR) << "Failed to load DIA data for \"" << file.value() << "\": "
  95    :                 << common::LogHr(hr) << ".";
  96  i :      return false;
  97    :    }
  98    :  
  99  E :    ScopedComPtr<IDiaSession> session;
 100  E :    hr = dia_source->openSession(session.Receive());
 101  E :    if (FAILED(hr)) {
 102  i :      LOG(ERROR) << "Failed to open DIA session for \"" << file.value() << "\" : "
 103    :                 << common::LogHr(hr) << ".";
 104  i :      return false;
 105    :    }
 106    :  
 107  E :    *dia_session = session.Detach();
 108    :  
 109  E :    return true;
 110  E :  }
 111    :  
 112    :  SearchResult FindDiaTable(const IID& iid,
 113    :                            IDiaSession* dia_session,
 114  E :                            void** out_table) {
 115  E :    DCHECK(dia_session != NULL);
 116  E :    DCHECK(out_table != NULL);
 117    :  
 118  E :    *out_table = NULL;
 119    :  
 120    :    // Get the table enumerator.
 121  E :    base::win::ScopedComPtr<IDiaEnumTables> enum_tables;
 122  E :    HRESULT hr = dia_session->getEnumTables(enum_tables.Receive());
 123  E :    if (FAILED(hr)) {
 124  i :      LOG(ERROR) << "Failed to get DIA table enumerator: "
 125    :                 << common::LogHr(hr) << ".";
 126  i :      return kSearchErrored;
 127    :    }
 128    :  
 129    :    // Iterate through the tables.
 130  E :    while (true) {
 131  E :      base::win::ScopedComPtr<IDiaTable> table;
 132  E :      ULONG fetched = 0;
 133  E :      hr = enum_tables->Next(1, table.Receive(), &fetched);
 134  E :      if (FAILED(hr)) {
 135  i :        LOG(ERROR) << "Failed to get DIA table: "
 136    :                   << common::LogHr(hr) << ".";
 137  i :        return kSearchErrored;
 138    :      }
 139  E :      if (fetched == 0)
 140  i :        break;
 141    :  
 142  E :      hr = table.QueryInterface(iid, out_table);
 143  E :      if (SUCCEEDED(hr))
 144  E :        return kSearchSucceeded;
 145  E :    }
 146    :  
 147    :    // The search completed, even though we didn't find what we were looking for.
 148  i :    return kSearchFailed;
 149  E :  }
 150    :  
 151    :  SearchResult FindDiaDebugStream(const wchar_t* name,
 152    :                                  IDiaSession* dia_session,
 153  E :                                  IDiaEnumDebugStreamData** dia_debug_stream) {
 154  E :    DCHECK(name != NULL);
 155  E :    DCHECK(dia_session != NULL);
 156  E :    DCHECK(dia_debug_stream != NULL);
 157    :  
 158  E :    *dia_debug_stream = NULL;
 159    :  
 160  E :    HRESULT hr = E_FAIL;
 161  E :    ScopedComPtr<IDiaEnumDebugStreams> debug_streams;
 162  E :    if (FAILED(hr = dia_session->getEnumDebugStreams(debug_streams.Receive()))) {
 163  i :      LOG(ERROR) << "Unable to get debug streams: " << common::LogHr(hr) << ".";
 164  i :      return kSearchErrored;
 165    :    }
 166    :  
 167    :    // Iterate through the debug streams.
 168  E :    while (true) {
 169  E :      ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
 170  E :      ULONG count = 0;
 171  E :      HRESULT hr = debug_streams->Next(1, debug_stream.Receive(), &count);
 172  E :      if (FAILED(hr) || (hr != S_FALSE && count != 1)) {
 173  i :        LOG(ERROR) << "Unable to load debug stream: "
 174    :                   << common::LogHr(hr) << ".";
 175  i :        return kSearchErrored;
 176  E :      } else if (hr == S_FALSE) {
 177    :        // No more records.
 178  E :        break;
 179    :      }
 180    :  
 181  E :      ScopedBstr stream_name;
 182  E :      if (FAILED(hr = debug_stream->get_name(stream_name.Receive()))) {
 183  i :        LOG(ERROR) << "Unable to get debug stream name: "
 184    :                   << common::LogHr(hr) << ".";
 185  i :        return kSearchErrored;
 186    :      }
 187    :  
 188    :      // Found the stream?
 189  E :      if (wcscmp(common::ToString(stream_name), name) == 0) {
 190  E :        *dia_debug_stream = debug_stream.Detach();
 191  E :        return kSearchSucceeded;
 192    :      }
 193  E :    }
 194    :  
 195  E :    return kSearchFailed;
 196  E :  }
 197    :  
 198    :  bool GetSymIndexId(IDiaSymbol* symbol, uint32_t* sym_index_id) {
 199    :    DCHECK(symbol);
 200    :    DCHECK(sym_index_id);
 201    :  
 202    :    DWORD index_id = 0;
 203    :    HRESULT hr = symbol->get_symIndexId(&index_id);
 204    :    if (hr != S_OK) {
 205    :      LOG(ERROR) << "Error getting symbol's index id. " << common::LogHr(hr);
 206    :      return false;
 207    :    }
 208    :  
 209    :    *sym_index_id = static_cast<uint32_t>(index_id);
 210    :    return true;
 211    :  }
 212    :  
 213  E :  bool GetSymTag(IDiaSymbol* symbol, enum SymTagEnum* sym_tag) {
 214  E :    DCHECK(symbol != NULL);
 215  E :    DCHECK(sym_tag != NULL);
 216  E :    DWORD tmp_tag = SymTagNull;
 217  E :    *sym_tag = SymTagNull;
 218  E :    HRESULT hr = symbol->get_symTag(&tmp_tag);
 219  E :    if (hr != S_OK) {
 220  i :      LOG(ERROR) << "Error getting sym tag: " << common::LogHr(hr) << ".";
 221  i :      return false;
 222    :    }
 223  E :    *sym_tag = static_cast<enum SymTagEnum>(tmp_tag);
 224  E :    return true;
 225  E :  }
 226    :  
 227  E :  bool IsSymTag(IDiaSymbol* symbol, enum SymTagEnum expected_sym_tag) {
 228  E :    DCHECK(symbol != NULL);
 229  E :    DCHECK(expected_sym_tag != SymTagNull);
 230    :  
 231  E :    enum SymTagEnum sym_tag = SymTagNull;
 232  E :    if (!GetSymTag(symbol, &sym_tag))
 233  i :      return false;
 234    :  
 235  E :    return sym_tag == expected_sym_tag;
 236  E :  }
 237    :  
 238    :  bool GetSymName(IDiaSymbol* symbol, base::string16* name) {
 239    :    DCHECK(symbol); DCHECK(name);
 240    :  
 241    :    base::win::ScopedBstr tmp;
 242    :    HRESULT hr = symbol->get_name(tmp.Receive());
 243    :    if (hr != S_OK) {
 244    :      LOG(ERROR) << "Error getting symbol's name: " << common::LogHr(hr) << ".";
 245    :      return false;
 246    :    }
 247    :  
 248    :    *name = common::ToString(tmp);
 249    :    return true;
 250    :  }
 251    :  
 252    :  bool GetSymUndecoratedName(IDiaSymbol* symbol, base::string16* name) {
 253    :    DCHECK(symbol); DCHECK(name);
 254    :  
 255    :    base::win::ScopedBstr tmp;
 256    :    HRESULT hr = symbol->get_undecoratedName(tmp.Receive());
 257    :    if (hr != S_OK) {
 258    :      LOG(ERROR) << "Error getting symbol's undecorated name: "
 259    :                 << common::LogHr(hr) << ".";
 260    :      return false;
 261    :    }
 262    :  
 263    :    *name = common::ToString(tmp);
 264    :    return true;
 265    :  }
 266    :  
 267    :  bool GetDataKind(IDiaSymbol* symbol, enum DataKind* data_kind) {
 268    :    DCHECK(symbol); DCHECK(data_kind);
 269    :  
 270    :    DWORD tmp = 0;
 271    :    HRESULT hr = symbol->get_dataKind(&tmp);
 272    :    if (hr != S_OK) {
 273    :      LOG(ERROR) << "Error getting symbol's data kind: " << common::LogHr(hr)
 274    :                 << ".";
 275    :      return false;
 276    :    }
 277    :  
 278    :    *data_kind = static_cast<DataKind>(tmp);
 279    :    return true;
 280    :  }
 281    :  
 282    :  bool GetLocationType(IDiaSymbol* symbol, enum LocationType* location_type) {
 283    :    DCHECK(symbol); DCHECK(location_type);
 284    :  
 285    :    DWORD tmp = 0;
 286    :    HRESULT hr = symbol->get_locationType(&tmp);
 287    :    if (hr != S_OK) {
 288    :      LOG(ERROR) << "Error getting symbol's location type: " << common::LogHr(hr)
 289    :                 << ".";
 290    :      return false;
 291    :    }
 292    :  
 293    :    *location_type = static_cast<LocationType>(tmp);
 294    :    return true;
 295    :  }
 296    :  
 297    :  bool GetRegisterId(IDiaSymbol* symbol, uint32_t* register_id) {
 298    :    DCHECK(symbol); DCHECK(register_id);
 299    :  
 300    :    DWORD tmp = 0;
 301    :    HRESULT hr = symbol->get_registerId(&tmp);
 302    :    if (hr != S_OK) {
 303    :      LOG(ERROR) << "Error getting symbol's register id: " << common::LogHr(hr)
 304    :                 << ".";
 305    :      return false;
 306    :    }
 307    :  
 308    :    *register_id = static_cast<uint32_t>(tmp);
 309    :    return true;
 310    :  }
 311    :  
 312    :  bool GetSymOffset(IDiaSymbol* symbol, ptrdiff_t* offset) {
 313    :    DCHECK(symbol); DCHECK(offset);
 314    :  
 315    :    LONG tmp = 0;
 316    :    HRESULT hr = symbol->get_offset(&tmp);
 317    :    if (hr != S_OK) {
 318    :      LOG(ERROR) << "Error getting symbol's offset: " << common::LogHr(hr) << ".";
 319    :      return false;
 320    :    }
 321    :  
 322    :    *offset = static_cast<ptrdiff_t>(tmp);
 323    :    return true;
 324    :  }
 325    :  
 326    :  bool GetSymType(IDiaSymbol* symbol, base::win::ScopedComPtr<IDiaSymbol>* type) {
 327    :    DCHECK(symbol); DCHECK(type);
 328    :  
 329    :    base::win::ScopedComPtr<IDiaSymbol> tmp;
 330    :    HRESULT hr = symbol->get_type(tmp.Receive());
 331    :    if (hr != S_OK) {
 332    :      LOG(ERROR) << "Error getting symbol's type: " << common::LogHr(hr) << ".";
 333    :      return false;
 334    :    }
 335    :  
 336    :    *type = tmp;
 337    :    return true;
 338    :  }
 339    :  
 340    :  bool GetSymQualifiers(IDiaSymbol* symbol, bool* is_const, bool* is_volatile) {
 341    :    DCHECK(symbol); DCHECK(is_const); DCHECK(is_volatile);
 342    :  
 343    :    BOOL is_const_tmp = FALSE;
 344    :    HRESULT hr = symbol->get_constType(&is_const_tmp);
 345    :    if (hr != S_OK)
 346    :      return false;
 347    :  
 348    :    BOOL is_volatile_tmp = FALSE;
 349    :    hr = symbol->get_volatileType(&is_volatile_tmp);
 350    :    if (hr != S_OK)
 351    :      return false;
 352    :  
 353    :    *is_const = (is_const_tmp == TRUE);
 354    :    *is_volatile = (is_volatile_tmp == TRUE);
 355    :    return true;
 356    :  }
 357    :  
 358    :  bool GetSymCount(IDiaSymbol* symbol, size_t* count) {
 359    :    DCHECK(symbol); DCHECK(count);
 360    :  
 361    :    DWORD tmp = 0;
 362    :    HRESULT hr = symbol->get_count(&tmp);
 363    :    if (hr != S_OK)
 364    :      return false;
 365    :  
 366    :    *count = static_cast<size_t>(tmp);
 367    :    return true;
 368    :  }
 369    :  
 370    :  bool GetSymClassParent(IDiaSymbol* symbol,
 371    :                         base::win::ScopedComPtr<IDiaSymbol>* parent) {
 372    :    DCHECK(symbol); DCHECK(parent);
 373    :    *parent = nullptr;
 374    :  
 375    :    base::win::ScopedComPtr<IDiaSymbol> tmp;
 376    :    HRESULT hr = symbol->get_classParent(tmp.Receive());
 377    :    if (hr == S_FALSE) {
 378    :      // This happens routinely for functions that aren't members.
 379    :      return true;
 380    :    }
 381    :    if (hr != S_OK) {
 382    :      LOG(ERROR) << "Error getting symbol's class parent: " << common::LogHr(hr)
 383    :                 << ".";
 384    :      return false;
 385    :    }
 386    :  
 387    :    *parent = tmp;
 388    :    return true;
 389    :  }
 390    :  
 391    :  bool GetSymLexicalParent(IDiaSymbol* symbol,
 392    :                           base::win::ScopedComPtr<IDiaSymbol>* parent) {
 393    :    DCHECK(symbol); DCHECK(parent);
 394    :  
 395    :    base::win::ScopedComPtr<IDiaSymbol> tmp;
 396    :    HRESULT hr = symbol->get_lexicalParent(tmp.Receive());
 397    :    if (hr != S_OK) {
 398    :      LOG(ERROR) << "Error getting symbol's lexical parent: " << common::LogHr(hr)
 399    :                 << ".";
 400    :      return false;
 401    :    }
 402    :  
 403    :    *parent = tmp;
 404    :    return true;
 405    :  }
 406    :  
 407    :  bool GetFrameBase(IDiaStackFrame* frame, uint64_t* frame_base) {
 408    :    DCHECK(frame != NULL);
 409    :    DCHECK(frame_base != NULL);
 410    :  
 411    :    ULONGLONG base = 0ULL;
 412    :    HRESULT hr = frame->get_base(&base);
 413    :    if (hr != S_OK) {
 414    :      LOG(ERROR) << "Failed to get stack frame's base address: "
 415    :                 << common::LogHr(hr) << ".";
 416    :      return false;
 417    :    }
 418    :  
 419    :    *frame_base = static_cast<uint64_t>(base);
 420    :    return true;
 421    :  }
 422    :  
 423    :  bool GetRegisterValue(IDiaStackFrame* frame,
 424    :                        CV_HREG_e register_index,
 425    :                        uint64_t* register_value) {
 426    :    DCHECK(frame != NULL);
 427    :    DCHECK(register_value != NULL);
 428    :  
 429    :    ULONGLONG value = 0ULL;
 430    :    HRESULT hr = frame->get_registerValue(register_index, &value);
 431    :    if (hr != S_OK) {
 432    :      // TODO(manzagop): print human readable register names.
 433    :      LOG(ERROR) << "Failed to get register value for index: "
 434    :                 << register_index << ". Error: " << common::LogHr(hr) << ".";
 435    :      return false;
 436    :    }
 437    :  
 438    :    *register_value = static_cast<uint64_t>(value);
 439    :    return true;
 440    :  }
 441    :  
 442    :  bool GetSize(IDiaStackFrame* frame, uint32_t* frame_size) {
 443    :    DCHECK(frame != NULL);
 444    :    DCHECK(frame_size != NULL);
 445    :  
 446    :    DWORD size = 0U;
 447    :    HRESULT hr = frame->get_size(&size);
 448    :    if (hr != S_OK) {
 449    :      LOG(ERROR) << "Failed to get frame size: " << common::LogHr(hr) << ".";
 450    :      return false;
 451    :    }
 452    :  
 453    :    *frame_size = static_cast<uint32_t>(size);
 454    :    return true;
 455    :  }
 456    :  
 457    :  bool GetLocalsBase(IDiaStackFrame* frame, uint64_t* locals_base) {
 458    :    DCHECK(frame != NULL);
 459    :    DCHECK(locals_base != NULL);
 460    :  
 461    :    ULONGLONG base = 0ULL;
 462    :    HRESULT hr = frame->get_localsBase(&base);
 463    :    if (hr != S_OK) {
 464    :      LOG(ERROR) << "Failed to get base address of locals: " << common::LogHr(hr)
 465    :                 << ".";
 466    :      return false;
 467    :    }
 468    :  
 469    :    *locals_base = static_cast<uint64_t>(base);
 470    :    return true;
 471    :  }
 472    :  
 473    :  ChildVisitor::ChildVisitor(IDiaSymbol* parent, enum SymTagEnum type)
 474  E :      : parent_(parent), type_(type), child_callback_(NULL) {
 475  E :    DCHECK(parent != NULL);
 476  E :  }
 477    :  
 478  E :  bool ChildVisitor::VisitChildren(const VisitSymbolCallback& child_callback) {
 479  E :    DCHECK(child_callback_ == NULL);
 480    :  
 481  E :    child_callback_ = &child_callback;
 482  E :    bool ret = VisitChildrenImpl();
 483  E :    child_callback_ = NULL;
 484    :  
 485  E :    return ret;
 486  E :  }
 487    :  
 488  E :  bool ChildVisitor::VisitChildrenImpl() {
 489  E :    DCHECK(child_callback_ != NULL);
 490    :  
 491    :    // Retrieve an enumerator for all children in this PDB.
 492  E :    base::win::ScopedComPtr<IDiaEnumSymbols> children;
 493  E :    HRESULT hr = parent_->findChildren(type_,
 494    :                                       NULL,
 495    :                                       nsNone,
 496    :                                       children.Receive());
 497  E :    if (FAILED(hr)) {
 498  i :      LOG(ERROR) << "Unable to get children: " << common::LogHr(hr);
 499  i :      return false;
 500    :    }
 501    :  
 502  E :    if (hr == S_FALSE)
 503  i :      return true;  // No child.
 504    :  
 505  E :    return EnumerateChildren(children.get());
 506  E :  }
 507    :  
 508  E :  bool ChildVisitor::EnumerateChildren(IDiaEnumSymbols* children) {
 509  E :    DCHECK(children!= NULL);
 510    :  
 511  E :    while (true) {
 512  E :      base::win::ScopedComPtr<IDiaSymbol> child;
 513  E :      ULONG fetched = 0;
 514  E :      HRESULT hr = children->Next(1, child.Receive(), &fetched);
 515  E :      if (FAILED(hr)) {
 516  i :        DCHECK_EQ(0U, fetched);
 517  i :        DCHECK(child.get() != nullptr);
 518  i :        LOG(ERROR) << "Unable to iterate children: " << common::LogHr(hr);
 519  i :        return false;
 520    :      }
 521  E :      if (hr == S_FALSE)
 522  E :        break;
 523    :  
 524  E :      DCHECK_EQ(1U, fetched);
 525  E :      DCHECK(child.get() != nullptr);
 526    :  
 527  E :      if (!VisitChild(child.get()))
 528  E :        return false;
 529  E :    }
 530    :  
 531  E :    return true;
 532  E :  }
 533    :  
 534  E :  bool ChildVisitor::VisitChild(IDiaSymbol* child) {
 535  E :    DCHECK(child_callback_ != NULL);
 536    :  
 537  E :    return child_callback_->Run(child);
 538  E :  }
 539    :  
 540  E :  CompilandVisitor::CompilandVisitor(IDiaSession* session) : session_(session) {
 541  E :    DCHECK(session != NULL);
 542  E :  }
 543    :  
 544    :  bool CompilandVisitor::VisitAllCompilands(
 545  E :      const VisitCompilandCallback& compiland_callback) {
 546  E :    base::win::ScopedComPtr<IDiaSymbol> global;
 547  E :    HRESULT hr = session_->get_globalScope(global.Receive());
 548  E :    if (FAILED(hr)) {
 549  i :      LOG(ERROR) << "Unable to get global scope: " << common::LogHr(hr);
 550  i :      return false;
 551    :    }
 552    :  
 553  E :    ChildVisitor visitor(global.get(), SymTagCompiland);
 554    :  
 555  E :    return visitor.VisitChildren(compiland_callback);
 556  E :  }
 557    :  
 558    :  LineVisitor::LineVisitor(IDiaSession* session, IDiaSymbol* compiland)
 559  E :      : session_(session), compiland_(compiland), line_callback_(NULL) {
 560  E :    DCHECK(session != NULL);
 561  E :  }
 562    :  
 563  E :  bool LineVisitor::VisitLines(const VisitLineCallback& line_callback) {
 564  E :    DCHECK(line_callback_ == NULL);
 565    :  
 566  E :    line_callback_ = &line_callback;
 567  E :    bool ret = VisitLinesImpl();
 568  E :    line_callback_ = NULL;
 569    :  
 570  E :    return ret;
 571  E :  }
 572    :  
 573    :  bool LineVisitor::EnumerateCompilandSource(IDiaSymbol* compiland,
 574  E :                                             IDiaSourceFile* source_file) {
 575  E :    DCHECK(compiland != NULL);
 576  E :    DCHECK(source_file != NULL);
 577    :  
 578  E :    base::win::ScopedComPtr<IDiaEnumLineNumbers> line_numbers;
 579  E :    HRESULT hr = session_->findLines(compiland,
 580    :                                     source_file,
 581    :                                     line_numbers.Receive());
 582  E :    if (FAILED(hr)) {
 583    :      // This seems to happen for the occasional header file.
 584  i :      return true;
 585    :    }
 586    :  
 587  E :    while (true) {
 588  E :      base::win::ScopedComPtr<IDiaLineNumber> line_number;
 589  E :      ULONG fetched = 0;
 590  E :      hr = line_numbers->Next(1, line_number.Receive(), &fetched);
 591  E :      if (FAILED(hr)) {
 592  i :        DCHECK_EQ(0U, fetched);
 593  i :        DCHECK(line_number.get() != nullptr);
 594  i :        LOG(ERROR) << "Unable to iterate line numbers: " << common::LogHr(hr);
 595  i :        return false;
 596    :      }
 597  E :      if (hr == S_FALSE)
 598  E :        break;
 599    :  
 600  E :      DCHECK_EQ(1U, fetched);
 601  E :      DCHECK(line_number.get() != nullptr);
 602    :  
 603  E :      if (!VisitSourceLine(line_number.get()))
 604  i :        return false;
 605  E :    }
 606    :  
 607  E :    return true;
 608  E :  }
 609    :  
 610    :  bool LineVisitor::EnumerateCompilandSources(IDiaSymbol* compiland,
 611  E :                                              IDiaEnumSourceFiles* source_files) {
 612  E :    DCHECK(compiland != NULL);
 613  E :    DCHECK(source_files != NULL);
 614    :  
 615  E :    while (true) {
 616  E :      base::win::ScopedComPtr<IDiaSourceFile> source_file;
 617  E :      ULONG fetched = 0;
 618  E :      HRESULT hr = source_files->Next(1, source_file.Receive(), &fetched);
 619  E :      if (FAILED(hr)) {
 620  i :        DCHECK_EQ(0U, fetched);
 621  i :        DCHECK(source_file == NULL);
 622  i :        LOG(ERROR) << "Unable to iterate source files: " << common::LogHr(hr);
 623  i :        return false;
 624    :      }
 625  E :      if (hr == S_FALSE)
 626  E :        break;
 627    :  
 628  E :      DCHECK_EQ(1U, fetched);
 629  E :      DCHECK(compiland != NULL);
 630    :  
 631  E :      if (!EnumerateCompilandSource(compiland, source_file.get()))
 632  i :        return false;
 633  E :    }
 634    :  
 635  E :    return true;
 636  E :  }
 637    :  
 638  E :  bool LineVisitor::VisitLinesImpl() {
 639  E :    DCHECK(session_ != NULL);
 640  E :    DCHECK(compiland_ != NULL);
 641  E :    DCHECK(line_callback_ != NULL);
 642    :  
 643    :    // Enumerate all source files referenced by this compiland.
 644  E :    base::win::ScopedComPtr<IDiaEnumSourceFiles> source_files;
 645  E :    HRESULT hr = session_->findFile(compiland_.get(), NULL, nsNone,
 646    :                                    source_files.Receive());
 647  E :    if (FAILED(hr)) {
 648  i :      LOG(ERROR) << "Unable to get source files: " << common::LogHr(hr);
 649  i :      return false;
 650    :    }
 651    :  
 652  E :    return EnumerateCompilandSources(compiland_.get(), source_files.get());
 653  E :  }
 654    :  
 655  E :  bool LineVisitor::VisitSourceLine(IDiaLineNumber* line_number) {
 656  E :    DCHECK(line_callback_ != NULL);
 657    :  
 658  E :    return line_callback_->Run(line_number);
 659  E :  }
 660    :  
 661    :  }  // namespace pe

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