Coverage for /Syzygy/refinery/analyzers/stack_frame_analyzer_impl.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%00151.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 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/refinery/analyzers/stack_frame_analyzer_impl.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/strings/stringprintf.h"
  20    :  #include "base/strings/utf_string_conversions.h"
  21    :  #include "syzygy/pe/dia_util.h"
  22    :  #include "syzygy/refinery/core/address.h"
  23    :  #include "syzygy/refinery/process_state/refinery.pb.h"
  24    :  #include "syzygy/refinery/types/type.h"
  25    :  #include "syzygy/refinery/types/type_namer.h"
  26    :  #include "third_party/cci/files/cvinfo.h"
  27    :  
  28  m :  namespace refinery {
  29    :  
  30  m :  namespace {
  31    :  
  32    :  // We observe that CV_ALLREG_VFRAME register-relative locations actually refer
  33    :  // to the parent frame's value.
  34  m :  bool GetRegRelLocationRegisterValue(StackFrameRecordPtr frame_record,
  35  m :                                      uint32_t register_id,
  36  m :                                      uint32_t* register_value) {
  37  m :    DCHECK(frame_record); DCHECK(register_value);
  38    :  
  39  m :    const RegisterInformation& context = frame_record->data().register_info();
  40    :    // Note: requests for CV_ALLREG_VFRAME are served with parent_allreg_vframe.
  41  m :    if (register_id == CV_ALLREG_VFRAME && context.has_parent_allreg_vframe()) {
  42  m :      *register_value = context.parent_allreg_vframe();
  43  m :      return true;
  44  m :    }
  45    :  
  46  m :    return false;
  47  m :  }
  48    :  
  49  m :  bool GetTypeName(IDiaSymbol* data, base::string16* type_name) {
  50  m :    DCHECK(data); DCHECK(type_name);
  51    :  
  52  m :    base::win::ScopedComPtr<IDiaSymbol> type;
  53  m :    if (!pe::GetSymType(data, &type))
  54  m :      return false;
  55    :  
  56  m :    return TypeNamer::GetTypeName(type.get(), type_name);
  57  m :  }
  58    :  
  59  m :  bool IsLocType(IDiaSymbol* data, LocationType type) {
  60  m :    DCHECK(data);
  61    :  
  62  m :    LocationType location_type = LocIsNull;
  63  m :    if (!pe::GetLocationType(data, &location_type))
  64  m :      return false;
  65    :  
  66  m :    return type == location_type;
  67  m :  }
  68    :  
  69  m :  bool GetDataType(TypeNameIndex* typename_index,
  70  m :                   IDiaSymbol* data,
  71  m :                   TypePtr* type) {
  72  m :    DCHECK(typename_index); DCHECK(data); DCHECK(type);
  73  m :    DCHECK(pe::IsSymTag(data, SymTagData));
  74  m :    *type = nullptr;
  75    :  
  76    :    // TODO(manzagop): stop relying on type name for retrieving the type once DIA
  77    :    // is no longer used and we have a stable id.
  78  m :    base::string16 type_name;
  79  m :    if (!GetTypeName(data, &type_name))
  80  m :      return false;
  81    :  
  82    :    // Retrieve symbol information.
  83  m :    std::vector<TypePtr> matching_types;
  84  m :    typename_index->GetTypes(type_name, &matching_types);
  85  m :    if (matching_types.empty()) {
  86  m :      VLOG(1) << "Type " << type_name << " was not found. Skipping.";
  87  m :      return true;
  88  m :    } else if (matching_types.size() > 1) {
  89    :      // We sometimes observe types that have the same name. See pdb_crawler for
  90    :      // details. All observed instances were for equivalent types. We therefore
  91    :      // return the first result.
  92    :      // TODO(manzagop): Deal with this, either by deduplication or minimally by
  93    :      // ensuring equality of the types. Also note that dia to TypeRepository
  94    :      // symbol matching is done using undecorated names; there may be some
  95    :      // legitimate name collisions.
  96  m :      VLOG(1) << "Multiple type matches for " << type_name;
  97  m :    }
  98    :  
  99  m :    *type = matching_types[0];
 100  m :    return true;
 101  m :  }
 102    :  
 103  m :  }  // namespace
 104    :  
 105  m :  StackFrameDataAnalyzer::StackFrameDataAnalyzer(
 106  m :      StackFrameRecordPtr frame_record,
 107  m :      scoped_refptr<TypeNameIndex> typename_index,
 108  m :      ModuleId module_id,
 109  m :      ProcessState* process_state)
 110  m :      : frame_record_(frame_record),
 111  m :        typename_index_(typename_index),
 112  m :        module_id_(module_id),
 113  m :        process_state_(process_state) {
 114  m :    DCHECK(frame_record.get());
 115  m :    DCHECK(typename_index.get());
 116  m :    DCHECK(process_state);
 117  m :  }
 118    :  
 119  m :  bool StackFrameDataAnalyzer::Analyze(IDiaSymbol* data) {
 120  m :    DCHECK(data);
 121  m :    DCHECK(pe::IsSymTag(data, SymTagData));
 122    :  
 123    :    // Restrict to local variables, parameters and this pointers.
 124    :    // TODO(manzagop): process other kinds, eg DataIsMember?
 125  m :    DataKind data_kind = DataIsUnknown;
 126  m :    if (!pe::GetDataKind(data, &data_kind))
 127  m :      return false;
 128  m :    switch (data_kind) {
 129  m :      case DataIsLocal:
 130  m :      case DataIsParam:
 131  m :      case DataIsObjectPtr:
 132  m :        break;
 133  m :      case DataIsUnknown:
 134  m :        return false;  // Should not happen.
 135  m :      case DataIsMember:
 136  m :      case DataIsStaticLocal:
 137  m :      case DataIsFileStatic:
 138  m :      case DataIsGlobal:
 139  m :      case DataIsStaticMember:
 140  m :      case DataIsConstant:
 141    :        // TODO(manzagop): look into these.
 142  m :        return true;  // Ignore these for now.
 143  m :    }
 144    :  
 145    :    // Get the data's information: name, type name and address range.
 146  m :    base::string16 data_name;
 147  m :    if (!pe::GetSymName(data, &data_name))
 148  m :      return false;
 149    :  
 150    :    // Get the data's type from the type_repository.
 151  m :    TypePtr type;
 152  m :    if (!GetDataType(typename_index_.get(), data, &type))
 153  m :      return false;
 154  m :    if (type.get() == nullptr)
 155  m :      return true;  // The type was not found.
 156    :  
 157  m :    AddressRange range;
 158  m :    if (!GetAddressRange(data, type, &range))
 159  m :      return false;
 160    :    // Note: successfully returning an invalid address range means the location
 161    :    // type is not yet supported.
 162    :    // TODO(manzagop): fully support location types and remove this.
 163  m :    if (!range.IsValid())
 164  m :      return true;
 165    :  
 166    :    // Add the typed block to the process state's typed block layer.
 167    :    // TODO(manzagop): handle CV qualifiers.
 168    :    // TODO(manzagop): avoid duplicating types we already know about.
 169  m :    return AddTypedBlockRecord(range, data_name, module_id_, type->type_id(),
 170  m :                               process_state_);
 171  m :  }
 172    :  
 173  m :  bool StackFrameDataAnalyzer::GetAddressRange(IDiaSymbol* data,
 174  m :                                               TypePtr type,
 175  m :                                               AddressRange* range) {
 176  m :    DCHECK(data); DCHECK(range);
 177    :  
 178  m :    LocationType location_type = LocIsNull;
 179  m :    if (!pe::GetLocationType(data, &location_type))
 180  m :      return false;
 181    :  
 182  m :    switch (location_type) {
 183  m :      case LocIsRegRel:
 184  m :        return GetAddressRangeRegRel(data, type, range);
 185  m :      case LocIsStatic:
 186  m :      case LocIsTLS:
 187  m :      case LocIsThisRel:
 188  m :      case LocIsEnregistered:
 189  m :      case LocIsBitField:
 190  m :      case LocIsSlot:
 191  m :      case LocIsIlRel:
 192  m :      case LocInMetaData:
 193  m :      case LocIsConstant:
 194  m :        VLOG(1) << "Unhandled location type: " << location_type;
 195    :        // TODO(manzagop): implement.
 196  m :        AddressRange address_range;
 197  m :        *range = address_range;
 198  m :        return true;
 199  m :    }
 200    :  
 201  m :    return false;
 202  m :  }
 203    :  
 204  m :  bool StackFrameDataAnalyzer::GetAddressRangeRegRel(IDiaSymbol* data,
 205  m :                                                     TypePtr type,
 206  m :                                                     AddressRange* range) {
 207  m :    DCHECK(data); DCHECK(range);
 208  m :    DCHECK(IsLocType(data, LocIsRegRel));
 209    :  
 210  m :    *range = AddressRange();
 211    :  
 212    :    // Register-relative: determine location.
 213  m :    uint32_t register_id = 0U;
 214  m :    if (!pe::GetRegisterId(data, &register_id))
 215  m :      return false;
 216  m :    ptrdiff_t register_offset = 0;
 217  m :    if (!pe::GetSymOffset(data, &register_offset))
 218  m :      return false;
 219    :  
 220    :    // Figure out the data's range.
 221  m :    uint32_t register_value = 0U;
 222  m :    if (!GetRegRelLocationRegisterValue(frame_record_, register_id,
 223  m :                                        &register_value)) {
 224  m :      LOG(ERROR) << base::StringPrintf(
 225  m :          "Failed to retrieve register value (%d). Skipping data.", register_id);
 226  m :      return true;
 227  m :    }
 228    :  
 229    :    // TODO(manzagop): check validity of operation.
 230  m :    Address data_va = register_value + register_offset;
 231  m :    AddressRange address_range(data_va, type->size());
 232  m :    if (!address_range.IsValid())
 233  m :      return false;
 234    :  
 235  m :    *range = address_range;
 236  m :    return true;
 237  m :  }
 238    :  
 239  m :  }  // namespace refinery

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