Coverage for /Syzygy/refinery/types/type_namer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
81.5%2653250.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/types/type_namer.h"
  16    :  
  17    :  #include <vector>
  18    :  
  19    :  #include "base/strings/string_util.h"
  20    :  #include "base/strings/stringprintf.h"
  21    :  #include "base/strings/utf_string_conversions.h"
  22    :  #include "syzygy/pe/dia_util.h"
  23    :  #include "third_party/cci/files/cvinfo.h"
  24    :  
  25    :  namespace refinery {
  26    :  
  27    :  namespace {
  28    :  
  29    :  namespace cci = Microsoft_Cci_Pdb;
  30    :  
  31  E :  base::string16 GetCVMod(bool is_const, bool is_volatile) {
  32  E :    base::string16 suffix;
  33  E :    if (is_const)
  34  E :      suffix += L" const";
  35  E :    if (is_volatile)
  36  E :      suffix += L" volatile";
  37  E :    return suffix;
  38  E :  }
  39    :  
  40    :  }  // namespace
  41    :  
  42  E :  bool GetSymBaseTypeName(IDiaSymbol* symbol, base::string16* type_name) {
  43  E :    DWORD base_type = 0;
  44  E :    HRESULT hr = symbol->get_baseType(&base_type);
  45  E :    if (hr != S_OK)
  46  i :      return false;
  47    :  
  48  E :    ULONGLONG length = 0;
  49  E :    hr = symbol->get_length(&length);
  50  E :    if (hr != S_OK)
  51  i :      return false;
  52    :  
  53    :    // TODO(siggi): What to do for these basic type names?
  54    :    //     One idea is to standardize on stdint.h types?
  55  E :    switch (base_type) {
  56    :      case btNoType:
  57  E :        *type_name = L"btNoType";
  58  E :        break;
  59    :      case btVoid:
  60  E :        *type_name = L"void";
  61  E :        break;
  62    :      case btChar:
  63  E :        *type_name = L"char";
  64  E :        break;
  65    :      case btWChar:
  66  E :        *type_name = L"wchar_t";
  67  E :        break;
  68    :      case btInt:
  69    :      case btLong: {
  70  E :        switch (length) {
  71    :          case 1:
  72  i :            *type_name = L"int8_t";
  73  i :            break;
  74    :          case 2:
  75  E :            *type_name = L"int16_t";
  76  E :            break;
  77    :          case 4:
  78  E :            *type_name = L"int32_t";
  79  E :            break;
  80    :          case 8:
  81  E :            *type_name = L"int64_t";
  82  E :            break;
  83    :  
  84    :          default:
  85  i :            return false;
  86    :        }
  87  E :        break;
  88    :      }
  89    :      case btUInt:
  90    :      case btULong: {
  91  E :        switch (length) {
  92    :          case 1:
  93  E :            *type_name = L"uint8_t";
  94  E :            break;
  95    :          case 2:
  96  E :            *type_name = L"uint16_t";
  97  E :            break;
  98    :          case 4:
  99  E :            *type_name = L"uint32_t";
 100  E :            break;
 101    :          case 8:
 102  E :            *type_name = L"uint64_t";
 103  E :            break;
 104    :  
 105    :          default:
 106  i :            return false;
 107    :        }
 108  E :        break;
 109    :      }
 110    :  
 111    :      case btFloat:
 112  E :        *type_name = L"float";
 113  E :        break;
 114    :      case btBCD:
 115  i :        *type_name = L"BCD";
 116  i :        break;
 117    :      case btBool:
 118  E :        *type_name = L"bool";
 119  E :        break;
 120    :      case btCurrency:
 121  i :        *type_name = L"Currency";
 122  i :        break;
 123    :      case btDate:
 124  i :        *type_name = L"Date";
 125  i :        break;
 126    :      case btVariant:
 127  i :        *type_name = L"Variant";
 128  i :        break;
 129    :      case btComplex:
 130  i :        *type_name = L"Complex";
 131  i :        break;
 132    :      case btBit:
 133  i :        *type_name = L"Bit";
 134  i :        break;
 135    :      case btBSTR:
 136  i :        *type_name = L"BSTR";
 137  i :        break;
 138    :      case btHresult:
 139  i :        *type_name = L"HRESULT";
 140  i :        break;
 141    :      default:
 142  i :        return false;
 143    :    }
 144    :  
 145  E :    return true;
 146  E :  }
 147    :  
 148    :  TypeNamer::TypeNamer(bool set_decorated_name)
 149  E :      : set_decorated_name_(set_decorated_name) {
 150  E :  }
 151    :  
 152  E :  TypeNamer::~TypeNamer() {
 153  E :  }
 154    :  
 155  E :  bool TypeNamer::EnsureTypeName(TypePtr type) const {
 156  E :    if (!type->name().empty())
 157  E :      return true;
 158    :  
 159  E :    switch (type->kind()) {
 160    :      case Type::POINTER_TYPE_KIND: {
 161  E :        PointerTypePtr ptr;
 162  E :        if (!type->CastTo(&ptr))
 163  i :          return false;
 164  E :        if (!AssignPointerName(ptr))
 165  i :          return false;
 166  E :        break;
 167    :      }
 168    :      case Type::ARRAY_TYPE_KIND: {
 169  E :        ArrayTypePtr array;
 170  E :        if (!type->CastTo(&array))
 171  i :          return false;
 172  E :        if (!AssignArrayName(array))
 173  i :          return false;
 174  E :        break;
 175    :      }
 176    :      case Type::FUNCTION_TYPE_KIND: {
 177  E :        FunctionTypePtr function;
 178  E :        if (!type->CastTo(&function))
 179  i :          return false;
 180  E :        if (!AssignFunctionName(function))
 181  i :          return false;
 182  E :        break;
 183    :      }
 184    :      case Type::USER_DEFINED_TYPE_KIND:
 185    :      case Type::BASIC_TYPE_KIND: {
 186    :        // These types should have their name set up.
 187    :        break;
 188    :      }
 189    :    }
 190    :  
 191  E :    DCHECK_NE(L"", type->name());
 192  E :    if (set_decorated_name_ && type->kind() != Type::BASIC_TYPE_KIND) {
 193  E :      DCHECK_NE(L"", type->decorated_name());
 194    :    }
 195    :  
 196  E :    return true;
 197  E :  }
 198    :  
 199  E :  bool TypeNamer::GetTypeName(IDiaSymbol* type, base::string16* type_name) {
 200  E :    DCHECK(type); DCHECK(type_name);
 201    :  
 202  E :    enum SymTagEnum sym_tag_type = SymTagNull;
 203  E :    if (!pe::GetSymTag(type, &sym_tag_type))
 204  i :      return false;
 205    :  
 206  E :    switch (sym_tag_type) {
 207    :      case SymTagUDT:
 208    :      case SymTagEnum:
 209    :      case SymTagTypedef:
 210    :      case SymTagData:
 211  E :        return pe::GetSymName(type, type_name);
 212    :      case SymTagBaseType:
 213  E :        return GetSymBaseTypeName(type, type_name);
 214    :      case SymTagPointerType:
 215  E :        return GetPointerName(type, type_name);
 216    :      case SymTagArrayType:
 217  E :        return GetArrayName(type, type_name);
 218    :      case SymTagFunctionType:
 219  E :        return GetFunctionName(type, type_name);
 220    :      case SymTagVTableShape:
 221    :      case SymTagVTable:
 222    :      default:
 223  i :        return false;
 224    :    }
 225  E :  }
 226    :  
 227  E :  bool TypeNamer::AssignPointerName(PointerTypePtr ptr) const {
 228  E :    base::string16 name;
 229  E :    base::string16 decorated_name;
 230    :  
 231    :    // Get the content type's name.
 232  E :    TypePtr content_type = ptr->GetContentType();
 233  E :    if (!content_type)
 234  i :      return false;
 235  E :    if (!EnsureTypeName(content_type))
 236  i :      return false;
 237  E :    name = content_type->name();
 238  E :    if (set_decorated_name_)
 239  E :      decorated_name = content_type->decorated_name();
 240    :  
 241    :    // Determine the suffix.
 242  E :    bool is_ref = (ptr->ptr_mode() != PointerType::PTR_MODE_PTR);
 243  E :    base::string16 suffix;
 244  E :    GetPointerNameSuffix(ptr->is_const(), ptr->is_volatile(), is_ref, &suffix);
 245    :  
 246    :    // Set the name.
 247  E :    name.append(suffix);
 248  E :    ptr->SetName(name);
 249  E :    if (set_decorated_name_) {
 250  E :      decorated_name.append(suffix);
 251  E :      ptr->SetDecoratedName(decorated_name);
 252    :    }
 253    :  
 254  E :    return true;
 255  E :  }
 256    :  
 257  E :  bool TypeNamer::AssignArrayName(ArrayTypePtr array) const {
 258  E :    base::string16 name;
 259  E :    base::string16 decorated_name;
 260    :  
 261  E :    TypePtr element_type = array->GetElementType();
 262  E :    if (!element_type)
 263  i :      return false;
 264  E :    if (!EnsureTypeName(element_type))
 265  i :      return false;
 266  E :    name = element_type->name();
 267  E :    if (set_decorated_name_)
 268  E :      decorated_name = element_type->decorated_name();
 269    :  
 270  E :    base::string16 suffix;
 271    :    GetArrayNameSuffix(array->is_const(), array->is_volatile(),
 272  E :                       array->num_elements(), &suffix);
 273    :  
 274  E :    name.append(suffix);
 275  E :    array->SetName(name);
 276  E :    if (set_decorated_name_) {
 277  E :      decorated_name.append(suffix);
 278  E :      array->SetDecoratedName(decorated_name);
 279    :    }
 280    :  
 281  E :    return true;
 282  E :  }
 283    :  
 284  E :  bool TypeNamer::AssignFunctionName(FunctionTypePtr function) const {
 285    :    // Start with the return type.
 286  E :    TypePtr return_type = function->GetReturnType();
 287  E :    base::string16 name;
 288  E :    base::string16 decorated_name;
 289  E :    if (!return_type)
 290  i :      return false;
 291  E :    if (!EnsureTypeName(return_type))
 292  i :      return false;
 293  E :    name = return_type->name();
 294  E :    if (set_decorated_name_)
 295  E :      decorated_name = return_type->decorated_name();
 296    :  
 297    :    base::string16 suffix = GetCVMod(function->return_type().is_const(),
 298  E :                                     function->return_type().is_volatile());
 299  E :    suffix.append(L" (");
 300    :  
 301  E :    name.append(suffix);
 302  E :    if (set_decorated_name_)
 303  E :      decorated_name.append(suffix);
 304    :  
 305    :    // Continue with containing class.
 306  E :    if (function->IsMemberFunction()) {
 307  E :      TypePtr class_type = function->GetContainingClassType();
 308  E :      if (!class_type)
 309  i :        return false;
 310  E :      if (!EnsureTypeName(class_type))
 311  i :        return false;
 312  E :      name.append(class_type->name() + L"::)(");
 313  E :      if (set_decorated_name_)
 314  E :        decorated_name.append(class_type->decorated_name() + L"::)(");
 315  E :    }
 316    :  
 317    :    // Get the argument types names.
 318  E :    std::vector<base::string16> arg_names;
 319  E :    std::vector<base::string16> arg_decorated_names;
 320  E :    for (size_t i = 0; i < function->argument_types().size(); ++i) {
 321  E :      TypePtr arg_type = function->GetArgumentType(i);
 322  E :      if (!arg_type)
 323  i :        return false;
 324  E :      if (!EnsureTypeName(arg_type))
 325  i :        return false;
 326    :  
 327    :      // Append the names, if the argument type is T_NOTYPE then this is a
 328    :      // C-style variadic function like printf and we append "..." instead.
 329  E :      if (arg_type->type_id() == cci::T_NOTYPE) {
 330  E :        arg_names.push_back(L"...");
 331  E :        if (set_decorated_name_)
 332  E :          arg_decorated_names.push_back(L"...");
 333  E :      } else {
 334  E :        const FunctionType::ArgumentType& arg = function->argument_types()[i];
 335  E :        base::string16 CV_mods = GetCVMod(arg.is_const(), arg.is_volatile());
 336  E :        arg_names.push_back(arg_type->name() + CV_mods);
 337  E :        if (set_decorated_name_)
 338  E :          arg_decorated_names.push_back(arg_type->decorated_name() + CV_mods);
 339  E :      }
 340  E :    }
 341    :  
 342  E :    name.append(base::JoinString(arg_names, L", "));
 343  E :    name.append(L")");
 344  E :    function->SetName(name);
 345  E :    if (set_decorated_name_) {
 346  E :      decorated_name.append(base::JoinString(arg_decorated_names, L", "));
 347  E :      decorated_name.append(L")");
 348  E :      function->SetDecoratedName(decorated_name);
 349    :    }
 350    :  
 351  E :    return true;
 352  E :  }
 353    :  
 354    :  void TypeNamer::GetPointerNameSuffix(bool is_const,
 355    :                                       bool is_volatile,
 356    :                                       bool is_ref,
 357  E :                                       base::string16* suffix) {
 358  E :    DCHECK(suffix);
 359    :  
 360  E :    *suffix = GetCVMod(is_const, is_volatile);
 361  E :    if (is_ref)
 362  E :      suffix->append(L"&");
 363  E :    else
 364  E :      suffix->append(L"*");
 365  E :  }
 366    :  
 367  E :  bool TypeNamer::GetPointerName(IDiaSymbol* type, base::string16* type_name) {
 368  E :    DCHECK(type); DCHECK(type_name);
 369  E :    DCHECK(pe::IsSymTag(type, SymTagPointerType));
 370    :  
 371  E :    base::string16 name;
 372    :  
 373    :    // Get the content type's name.
 374  E :    base::win::ScopedComPtr<IDiaSymbol> content_type;
 375  E :    if (!pe::GetSymType(type, &content_type))
 376  i :      return false;
 377  E :    if (!GetTypeName(content_type.get(), &name))
 378  i :      return false;
 379    :  
 380    :    // Determine the suffix.
 381  E :    bool is_const = false;
 382  E :    bool is_volatile = false;
 383  E :    if (!pe::GetSymQualifiers(content_type.get(), &is_const, &is_volatile))
 384  i :      return false;
 385    :    BOOL is_ref;
 386  E :    HRESULT hr = type->get_reference(&is_ref);
 387  E :    if (hr != S_OK)
 388  i :      return false;
 389    :  
 390  E :    base::string16 suffix;
 391  E :    GetPointerNameSuffix(is_const, is_volatile, is_ref == TRUE, &suffix);
 392    :  
 393    :    // Set the name.
 394  E :    name.append(suffix);
 395    :  
 396  E :    type_name->swap(name);
 397  E :    return true;
 398  E :  }
 399    :  
 400  E :  bool TypeNamer::GetArrayName(IDiaSymbol* type, base::string16* type_name) {
 401  E :    DCHECK(type); DCHECK(type_name);
 402  E :    DCHECK(pe::IsSymTag(type, SymTagArrayType));
 403    :  
 404    :    // Get the element type's name.
 405  E :    base::win::ScopedComPtr<IDiaSymbol> element_type;
 406  E :    if (!pe::GetSymType(type, &element_type))
 407  i :      return false;
 408  E :    base::string16 name;
 409  E :    if (!GetTypeName(element_type.get(), &name))
 410  i :      return false;
 411    :  
 412    :    // Determine the suffix.
 413  E :    bool is_const = false;
 414  E :    bool is_volatile = false;
 415  E :    if (!pe::GetSymQualifiers(element_type.get(), &is_const, &is_volatile))
 416  i :      return false;
 417  E :    size_t element_count = 0;
 418  E :    if (!pe::GetSymCount(type, &element_count))
 419  i :      return false;
 420  E :    base::string16 suffix;
 421  E :    GetArrayNameSuffix(is_const, is_volatile, element_count, &suffix);
 422    :  
 423    :    // Set the name.
 424  E :    name.append(suffix);
 425  E :    type_name->swap(name);
 426    :  
 427  E :    return true;
 428  E :  }
 429    :  
 430    :  // TODO(manzagop): function type name should include function's CV qualifiers?
 431  E :  bool TypeNamer::GetFunctionName(IDiaSymbol* type, base::string16* type_name) {
 432  E :    DCHECK(type); DCHECK(type_name);
 433  E :    DCHECK(pe::IsSymTag(type, SymTagFunctionType));
 434    :  
 435    :    // Start with the return type.
 436  E :    base::win::ScopedComPtr<IDiaSymbol> return_type;
 437  E :    if (!pe::GetSymType(type, &return_type))
 438  i :      return false;
 439  E :    base::string16 name;
 440  E :    if (!GetTypeName(return_type.get(), &name))
 441  i :      return false;
 442    :  
 443  E :    bool is_const = false;
 444  E :    bool is_volatile = false;
 445  E :    if (!pe::GetSymQualifiers(return_type.get(), &is_const, &is_volatile))
 446  i :      return false;
 447  E :    name.append(GetCVMod(is_const, is_volatile));
 448  E :    name.append(L" (");
 449    :  
 450    :    // Continue with containing class.
 451  E :    base::win::ScopedComPtr<IDiaSymbol> parent_type_sym;
 452  E :    if (!pe::GetSymClassParent(type, &parent_type_sym))
 453  i :      return false;
 454  E :    if (parent_type_sym.get() != nullptr) {
 455  E :      base::string16 class_name;
 456  E :      if (!GetTypeName(parent_type_sym.get(), &class_name))
 457  i :        return false;
 458  E :      name.append(class_name + L"::)(");
 459  E :    }
 460    :  
 461    :    // Get the argument types names.
 462  E :    size_t arg_count = 0;
 463  E :    if (!pe::GetSymCount(type, &arg_count))
 464  i :      return false;
 465    :  
 466  E :    base::win::ScopedComPtr<IDiaEnumSymbols> argument_types;
 467    :    HRESULT hr = type->findChildren(SymTagFunctionArgType, nullptr, nsNone,
 468  E :                                    argument_types.Receive());
 469  E :    if (!SUCCEEDED(hr))
 470  i :      return false;
 471    :  
 472  E :    std::vector<base::string16> arg_names;
 473  E :    base::win::ScopedComPtr<IDiaSymbol> arg_sym;
 474  E :    ULONG received = 0;
 475  E :    hr = argument_types->Next(1, arg_sym.Receive(), &received);
 476  E :    while (hr == S_OK) {
 477  E :      base::win::ScopedComPtr<IDiaSymbol> arg_type_sym;
 478  E :      if (!pe::GetSymType(arg_sym.get(), &arg_type_sym))
 479  i :        return false;
 480    :  
 481    :      // TODO(manzagop): look into how cci::T_NOTYPE fits in (C-style variadic
 482    :      // function).
 483  E :      base::string16 arg_name;
 484  E :      if (!GetTypeName(arg_type_sym.get(), &arg_name))
 485  i :        return false;
 486    :  
 487  E :      if (!pe::GetSymQualifiers(arg_type_sym.get(), &is_const, &is_volatile))
 488  i :        return false;
 489  E :      arg_name.append(GetCVMod(is_const, is_volatile));
 490    :  
 491  E :      arg_names.push_back(arg_name);
 492    :  
 493  E :      arg_sym.Release();
 494  E :      received = 0;
 495  E :      hr = argument_types->Next(1, arg_sym.Receive(), &received);
 496  E :    }
 497  E :    if (!SUCCEEDED(hr))
 498  i :      return false;
 499    :  
 500  E :    name.append(base::JoinString(arg_names, L", "));
 501  E :    name.append(L")");
 502    :  
 503  E :    type_name->swap(name);
 504  E :    return true;
 505  E :  }
 506    :  
 507    :  void TypeNamer::GetArrayNameSuffix(bool is_const,
 508    :                                     bool is_volatile,
 509    :                                     size_t count,
 510  E :                                     base::string16* suffix) {
 511  E :    DCHECK(suffix);
 512  E :    *suffix = GetCVMod(is_const, is_volatile);
 513  E :    base::StringAppendF(suffix, L"[%d]", count);
 514  E :  }
 515    :  
 516    :  }  // namespace refinery

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