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