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
|