Coverage for /Syzygy/pe/dia_util.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
81.4%1922360.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 "sawbuck/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"msdia100.dll";
  30    :  const wchar_t kFixupDiaDebugStreamName[] = L"FIXUP";
  31    :  const wchar_t kOmapToDiaDebugStreamName[] = L"OMAPTO";
  32    :  const wchar_t kOmapFromDiaDebugStreamName[] = L"OMAPFROM";
  33    :  
  34  E :  bool CreateDiaSource(IDiaDataSource** created_source) {
  35  E :    DCHECK(created_source != NULL);
  36    :  
  37  E :    *created_source = NULL;
  38    :  
  39  E :    ScopedComPtr<IDiaDataSource> dia_source;
  40  E :    HRESULT hr1 = dia_source.CreateInstance(CLSID_DiaSource);
  41  E :    if (SUCCEEDED(hr1)) {
  42  E :      *created_source = dia_source.Detach();
  43  E :      return true;
  44    :    }
  45    :  
  46    :    HRESULT hr2 = NoRegCoCreate(kDiaDllName,
  47    :                                CLSID_DiaSource,
  48    :                                IID_IDiaDataSource,
  49  E :                                reinterpret_cast<void**>(&dia_source));
  50  E :    if (SUCCEEDED(hr2)) {
  51  E :      *created_source = dia_source.Detach();
  52  E :      return true;
  53    :    }
  54    :  
  55  i :    LOG(ERROR) << "Failed to create DiaDataSource.";
  56  i :    LOG(ERROR) << "  CreateInstance failed with: " << com::LogHr(hr1);
  57  i :    LOG(ERROR) << "  NoRegCoCreate failed with: " << com::LogHr(hr2);
  58    :  
  59  i :    return false;
  60  E :  }
  61    :  
  62    :  bool CreateDiaSession(const base::FilePath& file,
  63    :                        IDiaDataSource* dia_source,
  64  E :                        IDiaSession** dia_session) {
  65  E :    DCHECK(dia_source != NULL);
  66  E :    DCHECK(dia_session != NULL);
  67    :  
  68  E :    *dia_session = NULL;
  69    :  
  70  E :    HRESULT hr = E_FAIL;
  71    :  
  72  E :    if (file.Extension() == L".pdb") {
  73  E :      hr = dia_source->loadDataFromPdb(file.value().c_str());
  74  E :    } else {
  75  E :      hr = dia_source->loadDataForExe(file.value().c_str(), NULL, NULL);
  76    :    }
  77    :  
  78  E :    if (FAILED(hr)) {
  79  i :      LOG(ERROR) << "Failed to load DIA data for \"" << file.value() << "\": "
  80    :                 << com::LogHr(hr) << ".";
  81  i :      return false;
  82    :    }
  83    :  
  84  E :    ScopedComPtr<IDiaSession> session;
  85  E :    hr = dia_source->openSession(session.Receive());
  86  E :    if (FAILED(hr)) {
  87  i :      LOG(ERROR) << "Failed to open DIA session for \"" << file.value() << "\" : "
  88    :                 << com::LogHr(hr) << ".";
  89  i :      return false;
  90    :    }
  91    :  
  92  E :    *dia_session = session.Detach();
  93    :  
  94  E :    return true;
  95  E :  }
  96    :  
  97    :  SearchResult FindDiaTable(const IID& iid,
  98    :                            IDiaSession* dia_session,
  99  E :                            void** out_table) {
 100  E :    DCHECK(dia_session != NULL);
 101  E :    DCHECK(out_table != NULL);
 102    :  
 103  E :    *out_table = NULL;
 104    :  
 105    :    // Get the table enumerator.
 106  E :    base::win::ScopedComPtr<IDiaEnumTables> enum_tables;
 107  E :    HRESULT hr = dia_session->getEnumTables(enum_tables.Receive());
 108  E :    if (FAILED(hr)) {
 109  i :      LOG(ERROR) << "Failed to get DIA table enumerator: "
 110    :                 << com::LogHr(hr) << ".";
 111  i :      return kSearchErrored;
 112    :    }
 113    :  
 114    :    // Iterate through the tables.
 115  E :    while (true) {
 116  E :      base::win::ScopedComPtr<IDiaTable> table;
 117  E :      ULONG fetched = 0;
 118  E :      hr = enum_tables->Next(1, table.Receive(), &fetched);
 119  E :      if (FAILED(hr)) {
 120  i :        LOG(ERROR) << "Failed to get DIA table: "
 121    :                   << com::LogHr(hr) << ".";
 122  i :        return kSearchErrored;
 123    :      }
 124  E :      if (fetched == 0)
 125  i :        break;
 126    :  
 127  E :      hr = table.QueryInterface(iid, out_table);
 128  E :      if (SUCCEEDED(hr))
 129  E :        return kSearchSucceeded;
 130  E :    }
 131    :  
 132    :    // The search completed, even though we didn't find what we were looking for.
 133  i :    return kSearchFailed;
 134  E :  }
 135    :  
 136    :  SearchResult FindDiaDebugStream(const wchar_t* name,
 137    :                                  IDiaSession* dia_session,
 138  E :                                  IDiaEnumDebugStreamData** dia_debug_stream) {
 139  E :    DCHECK(name != NULL);
 140  E :    DCHECK(dia_session != NULL);
 141  E :    DCHECK(dia_debug_stream != NULL);
 142    :  
 143  E :    *dia_debug_stream = NULL;
 144    :  
 145  E :    HRESULT hr = E_FAIL;
 146  E :    ScopedComPtr<IDiaEnumDebugStreams> debug_streams;
 147  E :    if (FAILED(hr = dia_session->getEnumDebugStreams(debug_streams.Receive()))) {
 148  i :      LOG(ERROR) << "Unable to get debug streams: " << com::LogHr(hr) << ".";
 149  i :      return kSearchErrored;
 150    :    }
 151    :  
 152    :    // Iterate through the debug streams.
 153  E :    while (true) {
 154  E :      ScopedComPtr<IDiaEnumDebugStreamData> debug_stream;
 155  E :      ULONG count = 0;
 156  E :      HRESULT hr = debug_streams->Next(1, debug_stream.Receive(), &count);
 157  E :      if (FAILED(hr) || (hr != S_FALSE && count != 1)) {
 158  i :        LOG(ERROR) << "Unable to load debug stream: "
 159    :                   << com::LogHr(hr) << ".";
 160  i :        return kSearchErrored;
 161  E :      } else if (hr == S_FALSE) {
 162    :        // No more records.
 163  E :        break;
 164    :      }
 165    :  
 166  E :      ScopedBstr stream_name;
 167  E :      if (FAILED(hr = debug_stream->get_name(stream_name.Receive()))) {
 168  i :        LOG(ERROR) << "Unable to get debug stream name: "
 169    :                   << com::LogHr(hr) << ".";
 170  i :        return kSearchErrored;
 171    :      }
 172    :  
 173    :      // Found the stream?
 174  E :      if (wcscmp(com::ToString(stream_name), name) == 0) {
 175  E :        *dia_debug_stream = debug_stream.Detach();
 176  E :        return kSearchSucceeded;
 177    :      }
 178  E :    }
 179    :  
 180  E :    return kSearchFailed;
 181  E :  }
 182    :  
 183  E :  bool GetSymTag(IDiaSymbol* symbol, enum SymTagEnum* sym_tag) {
 184  E :    DCHECK(symbol != NULL);
 185  E :    DCHECK(sym_tag != NULL);
 186  E :    DWORD tmp_tag = SymTagNull;
 187  E :    *sym_tag = SymTagNull;
 188  E :    HRESULT hr = symbol->get_symTag(&tmp_tag);
 189  E :    if (hr != S_OK) {
 190  i :      LOG(ERROR) << "Error getting sym tag: " << com::LogHr(hr) << ".";
 191  i :      return false;
 192    :    }
 193  E :    *sym_tag = static_cast<enum SymTagEnum>(tmp_tag);
 194  E :    return true;
 195  E :  }
 196    :  
 197  E :  bool IsSymTag(IDiaSymbol* symbol, enum SymTagEnum expected_sym_tag) {
 198  E :    DCHECK(symbol != NULL);
 199  E :    DCHECK(expected_sym_tag != SymTagNull);
 200    :  
 201  E :    enum SymTagEnum sym_tag = SymTagNull;
 202  E :    if (!GetSymTag(symbol, &sym_tag))
 203  i :      return false;
 204    :  
 205  E :    return sym_tag == expected_sym_tag;
 206  E :  }
 207    :  
 208    :  ChildVisitor::ChildVisitor(IDiaSymbol* parent, enum SymTagEnum type)
 209  E :      : parent_(parent), type_(type), child_callback_(NULL) {
 210  E :    DCHECK(parent != NULL);
 211  E :  }
 212    :  
 213  E :  bool ChildVisitor::VisitChildren(const VisitSymbolCallback& child_callback) {
 214  E :    DCHECK(child_callback_ == NULL);
 215    :  
 216  E :    child_callback_ = &child_callback;
 217  E :    bool ret = VisitChildrenImpl();
 218  E :    child_callback_ = NULL;
 219    :  
 220  E :    return ret;
 221  E :  }
 222    :  
 223  E :  bool ChildVisitor::VisitChildrenImpl() {
 224  E :    DCHECK(child_callback_ != NULL);
 225    :  
 226    :    // Retrieve an enumerator for all children in this PDB.
 227  E :    base::win::ScopedComPtr<IDiaEnumSymbols> children;
 228    :    HRESULT hr = parent_->findChildren(type_,
 229    :                                       NULL,
 230    :                                       nsNone,
 231  E :                                       children.Receive());
 232  E :    if (FAILED(hr)) {
 233  i :      LOG(ERROR) << "Unable to get children: " << com::LogHr(hr);
 234  i :      return false;
 235    :    }
 236    :  
 237  E :    return EnumerateChildren(children);
 238  E :  }
 239    :  
 240  E :  bool ChildVisitor::EnumerateChildren(IDiaEnumSymbols* children) {
 241  E :    DCHECK(children!= NULL);
 242    :  
 243  E :    while (true) {
 244  E :      base::win::ScopedComPtr<IDiaSymbol> child;
 245  E :      ULONG fetched = 0;
 246  E :      HRESULT hr = children->Next(1, child.Receive(), &fetched);
 247  E :      if (FAILED(hr)) {
 248  i :        DCHECK_EQ(0U, fetched);
 249  i :        DCHECK(child == NULL);
 250  i :        LOG(ERROR) << "Unable to iterate children: " << com::LogHr(hr);
 251  i :        return false;
 252    :      }
 253  E :      if (hr == S_FALSE)
 254  E :        break;
 255    :  
 256  E :      DCHECK_EQ(1U, fetched);
 257  E :      DCHECK(child != NULL);
 258    :  
 259  E :      if (!VisitChild(child))
 260  E :        return false;
 261  E :    }
 262    :  
 263  E :    return true;
 264  E :  }
 265    :  
 266  E :  bool ChildVisitor::VisitChild(IDiaSymbol* child) {
 267  E :    DCHECK(child_callback_ != NULL);
 268    :  
 269  E :    return child_callback_->Run(child);
 270  E :  }
 271    :  
 272  E :  CompilandVisitor::CompilandVisitor(IDiaSession* session) : session_(session) {
 273  E :    DCHECK(session != NULL);
 274  E :  }
 275    :  
 276    :  bool CompilandVisitor::VisitAllCompilands(
 277  E :      const VisitCompilandCallback& compiland_callback) {
 278  E :    base::win::ScopedComPtr<IDiaSymbol> global;
 279  E :    HRESULT hr = session_->get_globalScope(global.Receive());
 280  E :    if (FAILED(hr)) {
 281  i :      LOG(ERROR) << "Unable to get global scope: " << com::LogHr(hr);
 282  i :      return false;
 283    :    }
 284    :  
 285  E :    ChildVisitor visitor(global, SymTagCompiland);
 286    :  
 287  E :    return visitor.VisitChildren(compiland_callback);
 288  E :  }
 289    :  
 290    :  LineVisitor::LineVisitor(IDiaSession* session, IDiaSymbol* compiland)
 291  E :      : session_(session), compiland_(compiland), line_callback_(NULL) {
 292  E :    DCHECK(session != NULL);
 293  E :  }
 294    :  
 295  E :  bool LineVisitor::VisitLines(const VisitLineCallback& line_callback) {
 296  E :    DCHECK(line_callback_ == NULL);
 297    :  
 298  E :    line_callback_ = &line_callback;
 299  E :    bool ret = VisitLinesImpl();
 300  E :    line_callback_ = NULL;
 301    :  
 302  E :    return ret;
 303  E :  }
 304    :  
 305    :  bool LineVisitor::EnumerateCompilandSource(IDiaSymbol* compiland,
 306  E :                                             IDiaSourceFile* source_file) {
 307  E :    DCHECK(compiland != NULL);
 308  E :    DCHECK(source_file != NULL);
 309    :  
 310  E :    base::win::ScopedComPtr<IDiaEnumLineNumbers> line_numbers;
 311    :    HRESULT hr = session_->findLines(compiland,
 312    :                                     source_file,
 313  E :                                     line_numbers.Receive());
 314  E :    if (FAILED(hr)) {
 315    :      // This seems to happen for the occasional header file.
 316  i :      return true;
 317    :    }
 318    :  
 319  E :    while (true) {
 320  E :      base::win::ScopedComPtr<IDiaLineNumber> line_number;
 321  E :      ULONG fetched = 0;
 322  E :      hr = line_numbers->Next(1, line_number.Receive(), &fetched);
 323  E :      if (FAILED(hr)) {
 324  i :        DCHECK_EQ(0U, fetched);
 325  i :        DCHECK(line_number == NULL);
 326  i :        LOG(ERROR) << "Unable to iterate line numbers: " << com::LogHr(hr);
 327  i :        return false;
 328    :      }
 329  E :      if (hr == S_FALSE)
 330  E :        break;
 331    :  
 332  E :      DCHECK_EQ(1U, fetched);
 333  E :      DCHECK(line_number != NULL);
 334    :  
 335  E :      if (!VisitSourceLine(line_number))
 336  i :        return false;
 337  E :    }
 338    :  
 339  E :    return true;
 340  E :  }
 341    :  
 342    :  bool LineVisitor::EnumerateCompilandSources(IDiaSymbol* compiland,
 343  E :                                              IDiaEnumSourceFiles* source_files) {
 344  E :    DCHECK(compiland != NULL);
 345  E :    DCHECK(source_files != NULL);
 346    :  
 347  E :    while (true) {
 348  E :      base::win::ScopedComPtr<IDiaSourceFile> source_file;
 349  E :      ULONG fetched = 0;
 350  E :      HRESULT hr = source_files->Next(1, source_file.Receive(), &fetched);
 351  E :      if (FAILED(hr)) {
 352  i :        DCHECK_EQ(0U, fetched);
 353  i :        DCHECK(source_file == NULL);
 354  i :        LOG(ERROR) << "Unable to iterate source files: " << com::LogHr(hr);
 355  i :        return false;
 356    :      }
 357  E :      if (hr == S_FALSE)
 358  E :        break;
 359    :  
 360  E :      DCHECK_EQ(1U, fetched);
 361  E :      DCHECK(compiland != NULL);
 362    :  
 363  E :      if (!EnumerateCompilandSource(compiland, source_file))
 364  i :        return false;
 365  E :    }
 366    :  
 367  E :    return true;
 368  E :  }
 369    :  
 370  E :  bool LineVisitor::VisitLinesImpl() {
 371  E :    DCHECK(session_ != NULL);
 372  E :    DCHECK(compiland_ != NULL);
 373  E :    DCHECK(line_callback_ != NULL);
 374    :  
 375    :    // Enumerate all source files referenced by this compiland.
 376  E :    base::win::ScopedComPtr<IDiaEnumSourceFiles> source_files;
 377    :    HRESULT hr = session_->findFile(compiland_,
 378    :                                    NULL,
 379    :                                    nsNone,
 380  E :                                    source_files.Receive());
 381  E :    if (FAILED(hr)) {
 382  i :      LOG(ERROR) << "Unable to get source files: " << com::LogHr(hr);
 383  i :      return false;
 384    :    }
 385    :  
 386  E :    return EnumerateCompilandSources(compiland_, source_files);
 387  E :  }
 388    :  
 389  E :  bool LineVisitor::VisitSourceLine(IDiaLineNumber* line_number) {
 390  E :    DCHECK(line_callback_ != NULL);
 391    :  
 392  E :    return line_callback_->Run(line_number);
 393  E :  }
 394    :  
 395    :  }  // namespace pe

Coverage information generated Thu Jul 04 09:34:53 2013.