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