1 // Copyright (C) 2019 The Android Open Source Project
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 "repr/json/ir_dumper.h"
16
17 #include "repr/ir_dumper.h"
18 #include "repr/ir_representation.h"
19 #include "repr/json/api.h"
20 #include "repr/json/converter.h"
21
22 #include <json/writer.h>
23
24 #include <fstream>
25 #include <string>
26
27
28 namespace header_checker {
29 namespace repr {
30
31
AddAccess(JsonObject & type_decl,AccessSpecifierIR value)32 static void AddAccess(JsonObject &type_decl, AccessSpecifierIR value) {
33 if (value != default_access_ir) {
34 type_decl.Set("access",
35 FindInMap(access_ir_to_json, value,
36 "Failed to convert AccessSpecifierIR to JSON"));
37 }
38 }
39
AddRecordKind(JsonObject & record_type,RecordTypeIR::RecordKind value)40 static void AddRecordKind(JsonObject &record_type,
41 RecordTypeIR::RecordKind value) {
42 if (value != default_record_kind_ir) {
43 record_type.Set("record_kind",
44 FindInMap(record_kind_ir_to_json, value,
45 "Failed to convert RecordKind to JSON"));
46 }
47 }
48
AddAvailabilityAttrs(JsonObject & decl,const HasAvailabilityAttrs * decl_ir)49 static void AddAvailabilityAttrs(JsonObject &decl,
50 const HasAvailabilityAttrs *decl_ir) {
51 if (decl_ir->GetAvailabilityAttrs().empty()) {
52 return;
53 }
54 JsonArray attrs;
55 for (auto &&attr_ir : decl_ir->GetAvailabilityAttrs()) {
56 JsonObject attr;
57 if (auto introduced = attr_ir.GetIntroduced(); introduced.has_value()) {
58 attr.Set("introduced_major", (uint64_t)introduced.value());
59 }
60 if (auto deprecated = attr_ir.GetDeprecated(); deprecated.has_value()) {
61 attr.Set("deprecated_major", (uint64_t)deprecated.value());
62 }
63 if (auto obsoleted = attr_ir.GetObsoleted(); obsoleted.has_value()) {
64 attr.Set("obsoleted_major", (uint64_t)obsoleted.value());
65 }
66 if (attr_ir.IsUnavailable()) {
67 attr.Set("unavailable", true);
68 }
69 attrs.append(std::move(attr));
70 }
71 decl.Set("availability_attrs", attrs);
72 }
73
AddVtableComponentKind(JsonObject & vtable_component,VTableComponentIR::Kind value)74 static void AddVtableComponentKind(JsonObject &vtable_component,
75 VTableComponentIR::Kind value) {
76 if (value != default_vtable_component_kind_ir) {
77 vtable_component.Set(
78 "kind", FindInMap(vtable_component_kind_ir_to_json, value,
79 "Failed to convert VTableComponentIR::Kind to JSON"));
80 }
81 }
82
AddElfSymbolBinding(JsonObject & elf_symbol,ElfSymbolIR::ElfSymbolBinding value)83 static void AddElfSymbolBinding(JsonObject &elf_symbol,
84 ElfSymbolIR::ElfSymbolBinding value) {
85 if (value != default_elf_symbol_binding_ir) {
86 elf_symbol.Set("binding",
87 FindInMap(elf_symbol_binding_ir_to_json, value,
88 "Failed to convert ElfSymbolBinding to JSON"));
89 }
90 }
91
AddTemplateInfo(JsonObject & type_decl,const TemplatedArtifactIR * template_ir)92 static void AddTemplateInfo(JsonObject &type_decl,
93 const TemplatedArtifactIR *template_ir) {
94 JsonArray args;
95 for (auto &&template_element_ir : template_ir->GetTemplateElements()) {
96 args.append(template_element_ir.GetReferencedType());
97 }
98 type_decl.Set("template_args", args);
99 }
100
AddTypeInfo(JsonObject & type_decl,const TypeIR * type_ir)101 static void AddTypeInfo(JsonObject &type_decl, const TypeIR *type_ir) {
102 // LinkableMessageIR
103 type_decl.Set("source_file", type_ir->GetSourceFile());
104 const std::string &linker_set_key = type_ir->GetLinkerSetKey();
105 type_decl.Set("linker_set_key", linker_set_key);
106 // TypeIR
107 type_decl.Set("name", type_ir->GetName());
108 type_decl.Set("size", (uint64_t)type_ir->GetSize());
109 type_decl.Set("alignment", (uint64_t)type_ir->GetAlignment());
110 const std::string &self_type = type_ir->GetSelfType();
111 if (self_type != linker_set_key) {
112 type_decl.Set("self_type", self_type);
113 }
114 // ReferencesOtherType
115 const std::string &referenced_type = type_ir->GetReferencedType();
116 if (referenced_type != self_type) {
117 type_decl.Set("referenced_type", referenced_type);
118 }
119 }
120
ConvertRecordFieldIR(const RecordFieldIR * record_field_ir)121 static JsonObject ConvertRecordFieldIR(const RecordFieldIR *record_field_ir) {
122 JsonObject record_field;
123 record_field.Set("field_name", record_field_ir->GetName());
124 record_field.Set("referenced_type", record_field_ir->GetReferencedType());
125 AddAccess(record_field, record_field_ir->GetAccess());
126 record_field.Set("field_offset", (uint64_t)record_field_ir->GetOffset());
127 record_field.Set("is_bit_field", record_field_ir->IsBitField());
128 record_field.Set("bit_width", (uint64_t)record_field_ir->GetBitWidth());
129 AddAvailabilityAttrs(record_field, record_field_ir);
130 return record_field;
131 }
132
AddRecordFields(JsonObject & record_type,const RecordTypeIR * record_ir)133 static void AddRecordFields(JsonObject &record_type,
134 const RecordTypeIR *record_ir) {
135 JsonArray fields;
136 for (auto &&field_ir : record_ir->GetFields()) {
137 fields.append(ConvertRecordFieldIR(&field_ir));
138 }
139 record_type.Set("fields", fields);
140 }
141
142 static JsonObject
ConvertBaseSpecifierIR(const CXXBaseSpecifierIR & base_specifier_ir)143 ConvertBaseSpecifierIR(const CXXBaseSpecifierIR &base_specifier_ir) {
144 JsonObject base_specifier;
145 base_specifier.Set("referenced_type", base_specifier_ir.GetReferencedType());
146 base_specifier.Set("is_virtual", base_specifier_ir.IsVirtual());
147 AddAccess(base_specifier, base_specifier_ir.GetAccess());
148 return base_specifier;
149 }
150
AddBaseSpecifiers(JsonObject & record_type,const RecordTypeIR * record_ir)151 static void AddBaseSpecifiers(JsonObject &record_type,
152 const RecordTypeIR *record_ir) {
153 JsonArray base_specifiers;
154 for (auto &&base_ir : record_ir->GetBases()) {
155 base_specifiers.append(ConvertBaseSpecifierIR(base_ir));
156 }
157 record_type.Set("base_specifiers", base_specifiers);
158 }
159
160 static JsonObject
ConvertVTableComponentIR(const VTableComponentIR & vtable_component_ir)161 ConvertVTableComponentIR(const VTableComponentIR &vtable_component_ir) {
162 JsonObject vtable_component;
163 AddVtableComponentKind(vtable_component, vtable_component_ir.GetKind());
164 vtable_component.Set("component_value",
165 (int64_t)vtable_component_ir.GetValue());
166 vtable_component.Set("mangled_component_name", vtable_component_ir.GetName());
167 vtable_component.Set("is_pure", vtable_component_ir.GetIsPure());
168 return vtable_component;
169 }
170
AddVTableLayout(JsonObject & record_type,const RecordTypeIR * record_ir)171 static void AddVTableLayout(JsonObject &record_type,
172 const RecordTypeIR *record_ir) {
173 JsonArray vtable_components;
174 for (auto &&vtable_component_ir :
175 record_ir->GetVTableLayout().GetVTableComponents()) {
176 vtable_components.append(ConvertVTableComponentIR(vtable_component_ir));
177 }
178 record_type.Set("vtable_components", vtable_components);
179 }
180
ConvertRecordTypeIR(const RecordTypeIR * recordp)181 static JsonObject ConvertRecordTypeIR(const RecordTypeIR *recordp) {
182 JsonObject record_type;
183
184 AddAccess(record_type, recordp->GetAccess());
185 AddRecordKind(record_type, recordp->GetRecordKind());
186 record_type.Set("is_anonymous", recordp->IsAnonymous());
187 AddTypeInfo(record_type, recordp);
188 AddRecordFields(record_type, recordp);
189 AddBaseSpecifiers(record_type, recordp);
190 AddVTableLayout(record_type, recordp);
191 AddTemplateInfo(record_type, recordp);
192 AddAvailabilityAttrs(record_type, recordp);
193 return record_type;
194 }
195
AddFunctionParameters(JsonObject & function,const CFunctionLikeIR * cfunction_like_ir)196 static void AddFunctionParameters(JsonObject &function,
197 const CFunctionLikeIR *cfunction_like_ir) {
198 JsonArray parameters;
199 for (auto &¶meter_ir : cfunction_like_ir->GetParameters()) {
200 JsonObject parameter;
201 parameter.Set("referenced_type", parameter_ir.GetReferencedType());
202 parameter.Set("default_arg", parameter_ir.GetIsDefault());
203 parameter.Set("is_this_ptr", parameter_ir.GetIsThisPtr());
204 parameters.append(parameter);
205 }
206 function.Set("parameters", parameters);
207 }
208
AddFunctionParametersAndSetReturnType(JsonObject & function,const CFunctionLikeIR * cfunction_like_ir)209 static void AddFunctionParametersAndSetReturnType(
210 JsonObject &function, const CFunctionLikeIR *cfunction_like_ir) {
211 function.Set("return_type", cfunction_like_ir->GetReturnType());
212 AddFunctionParameters(function, cfunction_like_ir);
213 }
214
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)215 static JsonObject ConvertFunctionTypeIR(const FunctionTypeIR *function_typep) {
216 JsonObject function_type;
217 AddTypeInfo(function_type, function_typep);
218 AddFunctionParametersAndSetReturnType(function_type, function_typep);
219 return function_type;
220 }
221
ConvertFunctionIR(const FunctionIR * functionp)222 static JsonObject ConvertFunctionIR(const FunctionIR *functionp) {
223 JsonObject function;
224 AddAccess(function, functionp->GetAccess());
225 function.Set("linker_set_key", functionp->GetLinkerSetKey());
226 function.Set("source_file", functionp->GetSourceFile());
227 function.Set("function_name", functionp->GetName());
228 AddFunctionParametersAndSetReturnType(function, functionp);
229 AddTemplateInfo(function, functionp);
230 AddAvailabilityAttrs(function, functionp);
231 return function;
232 }
233
ConvertEnumFieldIR(const EnumFieldIR * enum_field_ir)234 static JsonObject ConvertEnumFieldIR(const EnumFieldIR *enum_field_ir) {
235 JsonObject enum_field;
236 enum_field.Set("name", enum_field_ir->GetName());
237 // Never omit enum values.
238 Json::Value &enum_field_value = enum_field["enum_field_value"];
239 if (enum_field_ir->IsSigned()) {
240 enum_field_value = Json::Int64(enum_field_ir->GetSignedValue());
241 } else {
242 enum_field_value = Json::UInt64(enum_field_ir->GetUnsignedValue());
243 }
244 AddAvailabilityAttrs(enum_field, enum_field_ir);
245 return enum_field;
246 }
247
AddEnumFields(JsonObject & enum_type,const EnumTypeIR * enum_ir)248 static void AddEnumFields(JsonObject &enum_type, const EnumTypeIR *enum_ir) {
249 JsonArray enum_fields;
250 for (auto &&field : enum_ir->GetFields()) {
251 enum_fields.append(ConvertEnumFieldIR(&field));
252 }
253 enum_type.Set("enum_fields", enum_fields);
254 }
255
ConvertEnumTypeIR(const EnumTypeIR * enump)256 static JsonObject ConvertEnumTypeIR(const EnumTypeIR *enump) {
257 JsonObject enum_type;
258 AddAccess(enum_type, enump->GetAccess());
259 enum_type.Set("underlying_type", enump->GetUnderlyingType());
260 AddTypeInfo(enum_type, enump);
261 AddEnumFields(enum_type, enump);
262 AddAvailabilityAttrs(enum_type, enump);
263 return enum_type;
264 }
265
ConvertGlobalVarIR(const GlobalVarIR * global_varp)266 static JsonObject ConvertGlobalVarIR(const GlobalVarIR *global_varp) {
267 JsonObject global_var;
268 // GlobalVarIR
269 global_var.Set("name", global_varp->GetName());
270 AddAccess(global_var, global_varp->GetAccess());
271 // LinkableMessageIR
272 global_var.Set("source_file", global_varp->GetSourceFile());
273 const std::string &linker_set_key = global_varp->GetLinkerSetKey();
274 global_var.Set("linker_set_key", linker_set_key);
275 // ReferencesOtherType
276 const std::string &referenced_type = global_varp->GetReferencedType();
277 if (linker_set_key != referenced_type) {
278 global_var.Set("referenced_type", referenced_type);
279 }
280 AddAvailabilityAttrs(global_var, global_varp);
281 return global_var;
282 }
283
ConvertPointerTypeIR(const PointerTypeIR * pointerp)284 static JsonObject ConvertPointerTypeIR(const PointerTypeIR *pointerp) {
285 JsonObject pointer_type;
286 AddTypeInfo(pointer_type, pointerp);
287 return pointer_type;
288 }
289
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)290 static JsonObject ConvertQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
291 JsonObject qualified_type;
292 AddTypeInfo(qualified_type, qualtypep);
293 qualified_type.Set("is_const", qualtypep->IsConst());
294 qualified_type.Set("is_volatile", qualtypep->IsVolatile());
295 qualified_type.Set("is_restricted", qualtypep->IsRestricted());
296 return qualified_type;
297 }
298
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)299 static JsonObject ConvertBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
300 JsonObject builtin_type;
301 builtin_type.Set("is_unsigned", builtin_typep->IsUnsigned());
302 builtin_type.Set("is_integral", builtin_typep->IsIntegralType());
303 AddTypeInfo(builtin_type, builtin_typep);
304 return builtin_type;
305 }
306
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)307 static JsonObject ConvertArrayTypeIR(const ArrayTypeIR *array_typep) {
308 JsonObject array_type;
309 array_type.Set("is_of_unknown_bound", array_typep->IsOfUnknownBound());
310 AddTypeInfo(array_type, array_typep);
311 return array_type;
312 }
313
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)314 static JsonObject ConvertLvalueReferenceTypeIR(
315 const LvalueReferenceTypeIR *lvalue_reference_typep) {
316 JsonObject lvalue_reference_type;
317 AddTypeInfo(lvalue_reference_type, lvalue_reference_typep);
318 return lvalue_reference_type;
319 }
320
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)321 static JsonObject ConvertRvalueReferenceTypeIR(
322 const RvalueReferenceTypeIR *rvalue_reference_typep) {
323 JsonObject rvalue_reference_type;
324 AddTypeInfo(rvalue_reference_type, rvalue_reference_typep);
325 return rvalue_reference_type;
326 }
327
AddLinkableMessageIR(const LinkableMessageIR * lm)328 bool JsonIRDumper::AddLinkableMessageIR(const LinkableMessageIR *lm) {
329 std::string key;
330 JsonObject converted;
331 // No RTTI
332 switch (lm->GetKind()) {
333 case RecordTypeKind:
334 key = "record_types";
335 converted = ConvertRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
336 break;
337 case EnumTypeKind:
338 key = "enum_types";
339 converted = ConvertEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
340 break;
341 case PointerTypeKind:
342 key = "pointer_types";
343 converted = ConvertPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
344 break;
345 case QualifiedTypeKind:
346 key = "qualified_types";
347 converted =
348 ConvertQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
349 break;
350 case ArrayTypeKind:
351 key = "array_types";
352 converted = ConvertArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
353 break;
354 case LvalueReferenceTypeKind:
355 key = "lvalue_reference_types";
356 converted = ConvertLvalueReferenceTypeIR(
357 static_cast<const LvalueReferenceTypeIR *>(lm));
358 break;
359 case RvalueReferenceTypeKind:
360 key = "rvalue_reference_types";
361 converted = ConvertRvalueReferenceTypeIR(
362 static_cast<const RvalueReferenceTypeIR *>(lm));
363 break;
364 case BuiltinTypeKind:
365 key = "builtin_types";
366 converted = ConvertBuiltinTypeIR(static_cast<const BuiltinTypeIR *>(lm));
367 break;
368 case FunctionTypeKind:
369 key = "function_types";
370 converted = ConvertFunctionTypeIR(static_cast<const FunctionTypeIR *>(lm));
371 break;
372 case GlobalVarKind:
373 key = "global_vars";
374 converted = ConvertGlobalVarIR(static_cast<const GlobalVarIR *>(lm));
375 break;
376 case FunctionKind:
377 key = "functions";
378 converted = ConvertFunctionIR(static_cast<const FunctionIR *>(lm));
379 break;
380 default:
381 return false;
382 }
383 translation_unit_[key].append(converted);
384 return true;
385 }
386
AddElfSymbolMessageIR(const ElfSymbolIR * elf_symbol_ir)387 bool JsonIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *elf_symbol_ir) {
388 std::string key;
389 switch (elf_symbol_ir->GetKind()) {
390 case ElfSymbolIR::ElfFunctionKind:
391 key = "elf_functions";
392 break;
393 case ElfSymbolIR::ElfObjectKind:
394 key = "elf_objects";
395 break;
396 default:
397 return false;
398 }
399 JsonObject elf_symbol;
400 elf_symbol.Set("name", elf_symbol_ir->GetName());
401 AddElfSymbolBinding(elf_symbol, elf_symbol_ir->GetBinding());
402 translation_unit_[key].append(elf_symbol);
403 return true;
404 }
405
DumpJson(const JsonObject & obj)406 static std::string DumpJson(const JsonObject &obj) {
407 Json::StreamWriterBuilder factory;
408 factory["indentation"] = " ";
409 return Json::writeString(factory, obj);
410 }
411
WriteTailTrimmedLinesToFile(const std::string & path,const std::string & output_string)412 static bool WriteTailTrimmedLinesToFile(const std::string &path,
413 const std::string &output_string) {
414 std::ofstream output_file(path);
415 size_t line_start = 0;
416 while (line_start < output_string.size()) {
417 size_t trailing_space_start = line_start;
418 size_t index;
419 for (index = line_start;
420 index < output_string.size() && output_string[index] != '\n';
421 index++) {
422 if (output_string[index] != ' ') {
423 trailing_space_start = index + 1;
424 }
425 }
426 // Only write this line if this line contains non-whitespace characters.
427 if (trailing_space_start != line_start) {
428 if (output_file
429 .write(output_string.data() + line_start,
430 trailing_space_start - line_start)
431 .fail()) {
432 return false;
433 }
434 if (output_file.write("\n", 1).fail()) {
435 return false;
436 }
437 }
438 line_start = index + 1;
439 }
440 return output_file.flush().good();
441 }
442
Dump(const ModuleIR & module)443 bool JsonIRDumper::Dump(const ModuleIR &module) {
444 DumpModule(module);
445 std::string output_string = DumpJson(translation_unit_);
446 return WriteTailTrimmedLinesToFile(dump_path_, output_string);
447 }
448
JsonIRDumper(const std::string & dump_path)449 JsonIRDumper::JsonIRDumper(const std::string &dump_path)
450 : IRDumper(dump_path), translation_unit_() {
451 const std::string keys[] = {
452 "record_types",
453 "enum_types",
454 "pointer_types",
455 "lvalue_reference_types",
456 "rvalue_reference_types",
457 "builtin_types",
458 "qualified_types",
459 "array_types",
460 "function_types",
461 "functions",
462 "global_vars",
463 "elf_functions",
464 "elf_objects",
465 };
466 for (auto key : keys) {
467 translation_unit_[key] = JsonArray();
468 }
469 }
470
CreateJsonIRDumper(const std::string & dump_path)471 std::unique_ptr<IRDumper> CreateJsonIRDumper(const std::string &dump_path) {
472 return std::make_unique<JsonIRDumper>(dump_path);
473 }
474
475
476 } // namespace repr
477 } // header_checker
478