Coverage for /Syzygy/grinder/line_info.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
78.2%1041330.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/grinder/line_info.h"
  16    :  
  17    :  #include <dia2.h>
  18    :  #include <algorithm>
  19    :  #include <limits>
  20    :  
  21    :  #include "base/strings/utf_string_conversions.h"
  22    :  #include "base/win/scoped_bstr.h"
  23    :  #include "base/win/scoped_comptr.h"
  24    :  #include "syzygy/common/com_utils.h"
  25    :  #include "syzygy/core/address_range.h"
  26    :  
  27    :  namespace grinder {
  28    :  
  29    :  namespace {
  30    :  
  31    :  using base::win::ScopedBstr;
  32    :  using base::win::ScopedComPtr;
  33    :  
  34    :  typedef core::AddressRange<core::RelativeAddress, size_t> RelativeAddressRange;
  35    :  typedef std::map<DWORD, const std::string*> SourceFileMap;
  36    :  
  37    :  bool GetDiaSessionForPdb(const base::FilePath& pdb_path,
  38    :                           IDiaDataSource* source,
  39  E :                           IDiaSession** session) {
  40  E :    DCHECK(source != NULL);
  41  E :    DCHECK(session != NULL);
  42    :  
  43  E :    HRESULT hr = source->loadDataFromPdb(pdb_path.value().c_str());
  44  E :    if (FAILED(hr)) {
  45  i :      LOG(ERROR) << "Failure in loadDataFromPdb: " << common::LogHr(hr) << ".";
  46  i :      return false;
  47    :    }
  48    :  
  49  E :    hr = source->openSession(session);
  50  E :    if (FAILED(hr)) {
  51  i :      LOG(ERROR) << "Failure in openSession: " << common::LogHr(hr) << ".";
  52  i :      return false;
  53    :    }
  54    :  
  55  E :    return true;
  56  E :  }
  57    :  
  58    :  
  59  E :  bool DisableOmapTranslation(IDiaSession* session) {
  60  E :    DCHECK(session != NULL);
  61    :  
  62  E :    ScopedComPtr<IDiaAddressMap> addr_map;
  63    :    HRESULT hr = session->QueryInterface(IID_IDiaAddressMap,
  64  E :                                         addr_map.ReceiveVoid());
  65  E :    if (FAILED(hr)) {
  66  i :      LOG(ERROR) << "Failure in QueryInterface: " << common::LogHr(hr) << ".";
  67  i :      return false;
  68    :    }
  69  E :    hr = addr_map->put_addressMapEnabled(FALSE);
  70  E :    if (FAILED(hr)) {
  71  i :      LOG(ERROR) << "Failure in put_addressMapEnabled: " << common::LogHr(hr)
  72    :                 << ".";
  73  i :      return false;
  74    :    }
  75    :  
  76  E :    return true;
  77  E :  }
  78    :  
  79    :  const std::string* GetSourceFileName(DWORD source_file_id,
  80    :                                       IDiaLineNumber* line_number,
  81    :                                       LineInfo::SourceFileSet* source_files,
  82  E :                                       SourceFileMap* source_file_map) {
  83  E :    DCHECK(line_number != NULL);
  84  E :    DCHECK(source_files != NULL);
  85  E :    DCHECK(source_file_map != NULL);
  86    :  
  87  E :    SourceFileMap::const_iterator map_it = source_file_map->find(source_file_id);
  88    :  
  89  E :    if (map_it != source_file_map->end())
  90  E :      return map_it->second;
  91    :  
  92  E :    ScopedComPtr<IDiaSourceFile> source_file;
  93  E :    HRESULT hr = line_number->get_sourceFile(source_file.Receive());
  94  E :    if (FAILED(hr)) {
  95  i :      LOG(ERROR) << "Failure in get_sourceFile: " << common::LogHr(hr) << ".";
  96  i :      return NULL;
  97    :    }
  98    :  
  99  E :    ScopedBstr source_file_path_bstr;
 100  E :    hr = source_file->get_fileName(source_file_path_bstr.Receive());
 101  E :    if (FAILED(hr)) {
 102  i :      LOG(ERROR) << "Failure in get_fileName: " << common::LogHr(hr) << ".";
 103  i :      return NULL;
 104    :    }
 105    :  
 106  E :    std::string source_file_path;
 107    :    if (!base::WideToUTF8(common::ToString(source_file_path_bstr),
 108    :                          source_file_path_bstr.Length(),
 109  E :                          &source_file_path)) {
 110  i :      LOG(ERROR) << "base::WideToUTF8 failed for path \""
 111    :                 << common::ToString(source_file_path_bstr) << "\".";
 112  i :      return NULL;
 113    :    }
 114    :  
 115    :    LineInfo::SourceFileSet::const_iterator source_file_it =
 116  E :        source_files->insert(source_file_path).first;
 117  E :    const std::string* source_file_name = &(*source_file_it);
 118    :    source_file_map->insert(std::make_pair(source_file_id,
 119  E :                                           source_file_name));
 120    :  
 121  E :    return source_file_name;
 122  E :  }
 123    :  
 124    :  // Used for comparing the ranges covered by two source lines.
 125    :  struct SourceLineAddressComparator {
 126    :    bool operator()(const LineInfo::SourceLine& sl1,
 127  E :                    const LineInfo::SourceLine& sl2) const {
 128  E :      return sl1.address + sl1.size <= sl2.address;
 129  E :    }
 130    :  };
 131    :  
 132    :  }  // namespace
 133    :  
 134  E :  bool LineInfo::Init(const base::FilePath& pdb_path) {
 135  E :    ScopedComPtr<IDiaDataSource> source;
 136  E :    HRESULT hr = source.CreateInstance(CLSID_DiaSource);
 137  E :    if (FAILED(hr)) {
 138  i :      LOG(ERROR) << "Failed to create DiaSource: " << common::LogHr(hr) << ".";
 139  i :      return false;
 140    :    }
 141    :  
 142  E :    ScopedComPtr<IDiaSession> session;
 143  E :    if (!GetDiaSessionForPdb(pdb_path, source.get(), session.Receive()))
 144  i :      return false;
 145    :  
 146    :    // We want original module addresses so we disable OMAP translation.
 147  E :    if (!DisableOmapTranslation(session.get()))
 148  i :      return false;
 149    :  
 150    :    // Get the line number enumeration.
 151  E :    ScopedComPtr<IDiaEnumLineNumbers> line_number_enum;
 152  E :    hr = session->findLinesByRVA(0, 0xFFFFFF, line_number_enum.Receive());
 153  E :    if (FAILED(hr)) {
 154  i :      LOG(ERROR) << "Failure in findLinesByRVA: " << common::LogHr(hr) << ".";
 155  i :      return false;
 156    :    }
 157    :  
 158    :    // A map of source file IDs we've already seen, mapping back to the source
 159    :    // file path. We use this as a cache so we're not constantly doing source-file
 160    :    // lookups while iterating.
 161  E :    SourceFileMap source_file_map;
 162    :  
 163    :    // Get the line info count and reserve space.
 164  E :    LONG line_number_count = 0;
 165  E :    hr = line_number_enum->get_Count(&line_number_count);
 166  E :    if (FAILED(hr)) {
 167  i :      LOG(ERROR) << "Failure in get_Count: " << common::LogHr(hr) << ".";
 168  i :      return false;
 169    :    }
 170  E :    source_lines_.reserve(line_number_count);
 171    :  
 172    :    // Iterate over the source line information.
 173  E :    DWORD old_source_file_id = SIZE_MAX;
 174  E :    DWORD old_rva = 0;
 175  E :    const std::string* source_file_name = NULL;
 176  E :    while (true) {
 177  E :      ScopedComPtr<IDiaLineNumber> line_number;
 178  E :      ULONG fetched = 0;
 179  E :      hr = line_number_enum->Next(1, line_number.Receive(), &fetched);
 180  E :      if (hr != S_OK || fetched != 1)
 181  E :        break;
 182    :  
 183  E :      DWORD source_file_id = 0;
 184  E :      hr = line_number->get_sourceFileId(&source_file_id);
 185  E :      if (FAILED(hr)) {
 186  i :        LOG(ERROR) << "Failure in get_sourceFileId: " << common::LogHr(hr) << ".";
 187  i :        return false;
 188    :      }
 189    :  
 190    :      // Look for the source file by ID. Since we most often see successive
 191    :      // lines from the same file we have a shortcut to avoid extra processing in
 192    :      // this case.
 193  E :      if (source_file_id != old_source_file_id) {
 194    :        source_file_name = GetSourceFileName(source_file_id,
 195    :                                             line_number.get(),
 196    :                                             &source_files_,
 197  E :                                             &source_file_map);
 198    :      }
 199  E :      old_source_file_id = source_file_id;
 200  E :      DCHECK(source_file_name != NULL);
 201    :  
 202  E :      DWORD line = 0;
 203  E :      DWORD rva = 0;
 204  E :      DWORD length = 0;
 205    :      if (FAILED(line_number->get_lineNumber(&line)) ||
 206    :          FAILED(line_number->get_relativeVirtualAddress(&rva)) ||
 207  E :          FAILED(line_number->get_length(&length))) {
 208  i :        LOG(ERROR) << "Failed to get line number properties.";
 209  i :        return false;
 210    :      }
 211    :  
 212    :      // We rely on the enumeration returning us lines in order of increasing
 213    :      // address, as they are stored originally in the PDB. This is required for
 214    :      // the following zero-length fixing mechanism to work as intended.
 215  E :      DCHECK_LE(old_rva, rva);
 216  E :      old_rva = rva;
 217    :  
 218    :      // Is this a non-zero length? Back up and make any zero-length ranges
 219    :      // with the same start address the same length as us. This makes them
 220    :      // simply look like repeated entries in the array and makes searching for
 221    :      // them with lower_bound/upper_bound work as expected.
 222  E :      if (length != 0) {
 223  E :        SourceLines::reverse_iterator it = source_lines_.rbegin();
 224  E :        for (; it != source_lines_.rend(); ++it) {
 225  E :          if (it->size != 0)
 226  E :            break;
 227  E :          if (it->address.value() != rva) {
 228  i :            LOG(ERROR) << "Encountered zero-length line number with "
 229    :                       << "inconsistent address.";
 230  i :            return false;
 231    :          }
 232  E :          it->size = length;
 233  E :        }
 234    :      }
 235    :  
 236    :      source_lines_.push_back(SourceLine(source_file_name,
 237    :                                         line,
 238    :                                         core::RelativeAddress(rva),
 239  E :                                         length));
 240  E :    }
 241    :  
 242  E :    return true;
 243  E :  }
 244    :  
 245    :  bool LineInfo::Visit(
 246  E :      core::RelativeAddress address, size_t size, size_t count) {
 247    :    // Visiting a range of size zero is a nop.
 248  E :    if (size == 0)
 249  i :      return true;
 250    :  
 251    :    // Create a dummy 'source line' for the search.
 252  E :    SourceLine visit_source_line(NULL, 0, address, size);
 253    :  
 254    :    SourceLines::iterator begin_it =
 255    :        std::lower_bound(source_lines_.begin(),
 256    :                         source_lines_.end(),
 257    :                         visit_source_line,
 258  E :                         SourceLineAddressComparator());
 259    :  
 260    :    SourceLines::iterator end_it =
 261    :        std::upper_bound(source_lines_.begin(),
 262    :                         source_lines_.end(),
 263    :                         visit_source_line,
 264  E :                         SourceLineAddressComparator());
 265    :  
 266  E :    SourceLines::iterator it = begin_it;
 267  E :    RelativeAddressRange visit(address, size);
 268  E :    for (; it != end_it; ++it) {
 269  E :      RelativeAddressRange range(it->address, it->size);
 270  E :      if (visit.Intersects(range)) {
 271    :        // We use saturation arithmetic here as overflow is a real possibility in
 272    :        // long trace files.
 273    :        it->visit_count =
 274    :            std::min(it->visit_count,
 275  E :                     std::numeric_limits<uint32>::max() - count) + count;
 276    :      }
 277  E :    }
 278    :  
 279  E :    return true;
 280  E :  }
 281    :  
 282    :  }  // namespace grinder

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