Coverage for /Syzygy/pe/dia_util.cc

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

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