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