• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/protobuf/ir_dumper.h"
16 
17 #include "repr/protobuf/abi_dump.h"
18 #include "repr/protobuf/api.h"
19 
20 #include <fstream>
21 #include <memory>
22 
23 #include <llvm/Support/raw_ostream.h>
24 
25 #include <google/protobuf/io/zero_copy_stream_impl.h>
26 #include <google/protobuf/text_format.h>
27 
28 
29 namespace header_checker {
30 namespace repr {
31 
32 
AddTemplateInformation(abi_dump::TemplateInfo * ti,const TemplatedArtifactIR * ta)33 bool IRToProtobufConverter::AddTemplateInformation(
34     abi_dump::TemplateInfo *ti, const TemplatedArtifactIR *ta) {
35   for (auto &&template_element : ta->GetTemplateElements()) {
36     abi_dump::TemplateElement *added_element = ti->add_elements();
37     if (!added_element) {
38       llvm::errs() << "Failed to add template element\n";
39       return false;
40     }
41     added_element->set_referenced_type(template_element.GetReferencedType());
42   }
43   return true;
44 }
45 
AddTypeInfo(abi_dump::BasicNamedAndTypedDecl * type_info,const TypeIR * typep)46 bool IRToProtobufConverter::AddTypeInfo(
47     abi_dump::BasicNamedAndTypedDecl *type_info, const TypeIR *typep) {
48   if (!type_info || !typep) {
49     llvm::errs() << "Typeinfo not valid\n";
50     return false;
51   }
52   type_info->set_linker_set_key(typep->GetLinkerSetKey());
53   type_info->set_source_file(typep->GetSourceFile());
54   type_info->set_name(typep->GetName());
55   type_info->set_size(typep->GetSize());
56   type_info->set_alignment(typep->GetAlignment());
57   type_info->set_referenced_type(typep->GetReferencedType());
58   type_info->set_self_type(typep->GetSelfType());
59   return true;
60 }
61 
AddRecordFields(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)62 bool IRToProtobufConverter::AddRecordFields(
63     abi_dump::RecordType *record_protobuf,
64     const RecordTypeIR *record_ir) {
65   // Iterate through the fields and create corresponding ones for the protobuf
66   // record
67   for (auto &&field_ir : record_ir->GetFields()) {
68     abi_dump::RecordFieldDecl *added_field = record_protobuf->add_fields();
69     if (!added_field) {
70       llvm::errs() << "Couldn't add record field\n";
71     }
72     SetIRToProtobufRecordField(added_field, &field_ir);
73   }
74   return true;
75 }
76 
AddBaseSpecifiers(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)77 bool IRToProtobufConverter::AddBaseSpecifiers(
78     abi_dump::RecordType *record_protobuf, const RecordTypeIR *record_ir) {
79   for (auto &&base_ir : record_ir->GetBases()) {
80     abi_dump::CXXBaseSpecifier *added_base =
81         record_protobuf->add_base_specifiers();
82     if (!SetIRToProtobufBaseSpecifier(added_base, base_ir)) {
83       return false;
84     }
85   }
86   return true;
87 }
88 
AddVTableLayout(abi_dump::RecordType * record_protobuf,const RecordTypeIR * record_ir)89 bool IRToProtobufConverter::AddVTableLayout(
90     abi_dump::RecordType *record_protobuf,
91     const RecordTypeIR *record_ir) {
92   // If there are no entries in the vtable, just return.
93   if (record_ir->GetVTableNumEntries() == 0) {
94     return true;
95   }
96   const VTableLayoutIR &vtable_layout_ir = record_ir->GetVTableLayout();
97   abi_dump::VTableLayout *vtable_layout_protobuf =
98       record_protobuf->mutable_vtable_layout();
99   if (!SetIRToProtobufVTableLayout(vtable_layout_protobuf, vtable_layout_ir)) {
100     return false;
101   }
102   return true;
103 }
104 
AddTagTypeInfo(abi_dump::TagType * tag_type_protobuf,const TagTypeIR * tag_type_ir)105 bool IRToProtobufConverter::AddTagTypeInfo(
106     abi_dump::TagType *tag_type_protobuf,
107     const TagTypeIR *tag_type_ir) {
108   if (!tag_type_protobuf || !tag_type_ir) {
109     return false;
110   }
111   tag_type_protobuf->set_unique_id(tag_type_ir->GetUniqueId());
112   return true;
113 }
114 
ConvertRecordTypeIR(const RecordTypeIR * recordp)115 abi_dump::RecordType IRToProtobufConverter::ConvertRecordTypeIR(
116     const RecordTypeIR *recordp) {
117   abi_dump::RecordType added_record_type;
118   added_record_type.set_access(AccessIRToProtobuf(recordp->GetAccess()));
119   added_record_type.set_record_kind(
120       RecordKindIRToProtobuf(recordp->GetRecordKind()));
121   if (recordp->IsAnonymous()) {
122     added_record_type.set_is_anonymous(true);
123   }
124   if (!AddTypeInfo(added_record_type.mutable_type_info(), recordp) ||
125       !AddRecordFields(&added_record_type, recordp) ||
126       !AddBaseSpecifiers(&added_record_type, recordp) ||
127       !AddVTableLayout(&added_record_type, recordp) ||
128       !AddTagTypeInfo(added_record_type.mutable_tag_info(), recordp) ||
129       !(recordp->GetTemplateElements().size() ?
130         AddTemplateInformation(added_record_type.mutable_template_info(),
131                                recordp) : true)) {
132     llvm::errs() << "Template information could not be added\n";
133     ::exit(1);
134   }
135   return added_record_type;
136 }
137 
138 
ConvertElfObjectIR(const ElfObjectIR * elf_object_ir)139 abi_dump::ElfObject IRToProtobufConverter::ConvertElfObjectIR(
140     const ElfObjectIR *elf_object_ir) {
141   abi_dump::ElfObject elf_object_protobuf;
142   elf_object_protobuf.set_name(elf_object_ir->GetName());
143   return elf_object_protobuf;
144 }
145 
ConvertElfFunctionIR(const ElfFunctionIR * elf_function_ir)146 abi_dump::ElfFunction IRToProtobufConverter::ConvertElfFunctionIR(
147     const ElfFunctionIR *elf_function_ir) {
148   abi_dump::ElfFunction elf_function_protobuf;
149   elf_function_protobuf.set_name(elf_function_ir->GetName());
150   return elf_function_protobuf;
151 }
152 
153 template <typename CFunctionLikeMessage>
AddFunctionParametersAndSetReturnType(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)154 bool IRToProtobufConverter::AddFunctionParametersAndSetReturnType(
155     CFunctionLikeMessage *function_like_protobuf,
156     const CFunctionLikeIR *cfunction_like_ir) {
157   function_like_protobuf->set_return_type(cfunction_like_ir->GetReturnType());
158   return AddFunctionParameters(function_like_protobuf, cfunction_like_ir);
159 }
160 
161 template <typename CFunctionLikeMessage>
AddFunctionParameters(CFunctionLikeMessage * function_like_protobuf,const CFunctionLikeIR * cfunction_like_ir)162 bool IRToProtobufConverter::AddFunctionParameters(
163     CFunctionLikeMessage *function_like_protobuf,
164     const CFunctionLikeIR *cfunction_like_ir) {
165   for (auto &&parameter : cfunction_like_ir->GetParameters()) {
166     abi_dump::ParamDecl *added_parameter =
167         function_like_protobuf->add_parameters();
168     if (!added_parameter) {
169       return false;
170     }
171     added_parameter->set_referenced_type(
172         parameter.GetReferencedType());
173     added_parameter->set_default_arg(parameter.GetIsDefault());
174     added_parameter->set_is_this_ptr(parameter.GetIsThisPtr());
175   }
176   return true;
177 }
178 
ConvertFunctionTypeIR(const FunctionTypeIR * function_typep)179 abi_dump::FunctionType IRToProtobufConverter::ConvertFunctionTypeIR (
180     const FunctionTypeIR *function_typep) {
181   abi_dump::FunctionType added_function_type;
182   if (!AddTypeInfo(added_function_type.mutable_type_info(), function_typep) ||
183       !AddFunctionParametersAndSetReturnType(&added_function_type,
184                                              function_typep)) {
185     llvm::errs() << "Could not convert FunctionTypeIR to protobuf\n";
186     ::exit(1);
187   }
188   return added_function_type;
189 }
190 
ConvertFunctionIR(const FunctionIR * functionp)191 abi_dump::FunctionDecl IRToProtobufConverter::ConvertFunctionIR(
192     const FunctionIR *functionp) {
193   abi_dump::FunctionDecl added_function;
194   added_function.set_access(AccessIRToProtobuf(functionp->GetAccess()));
195   added_function.set_linker_set_key(functionp->GetLinkerSetKey());
196   added_function.set_source_file(functionp->GetSourceFile());
197   added_function.set_function_name(functionp->GetName());
198   if (!AddFunctionParametersAndSetReturnType(&added_function, functionp) ||
199       !(functionp->GetTemplateElements().size() ?
200       AddTemplateInformation(added_function.mutable_template_info(), functionp)
201       : true)) {
202     llvm::errs() << "Template information could not be added\n";
203     ::exit(1);
204   }
205   return added_function;
206 }
207 
AddEnumFields(abi_dump::EnumType * enum_protobuf,const EnumTypeIR * enum_ir)208 bool IRToProtobufConverter::AddEnumFields(abi_dump::EnumType *enum_protobuf,
209                                           const EnumTypeIR *enum_ir) {
210   for (auto &&field : enum_ir->GetFields()) {
211     abi_dump::EnumFieldDecl *enum_fieldp = enum_protobuf->add_enum_fields();
212     if (!SetIRToProtobufEnumField(enum_fieldp, &field)) {
213       return false;
214     }
215   }
216   return true;
217 }
218 
219 
ConvertEnumTypeIR(const EnumTypeIR * enump)220 abi_dump::EnumType IRToProtobufConverter::ConvertEnumTypeIR(
221     const EnumTypeIR *enump) {
222   abi_dump::EnumType added_enum_type;
223   added_enum_type.set_access(AccessIRToProtobuf(enump->GetAccess()));
224   added_enum_type.set_underlying_type(enump->GetUnderlyingType());
225   if (!AddTypeInfo(added_enum_type.mutable_type_info(), enump) ||
226       !AddEnumFields(&added_enum_type, enump) ||
227       !AddTagTypeInfo(added_enum_type.mutable_tag_info(), enump)) {
228     llvm::errs() << "EnumTypeIR could not be converted\n";
229     ::exit(1);
230   }
231   return added_enum_type;
232 }
233 
ConvertGlobalVarIR(const GlobalVarIR * global_varp)234 abi_dump::GlobalVarDecl IRToProtobufConverter::ConvertGlobalVarIR(
235     const GlobalVarIR *global_varp) {
236   abi_dump::GlobalVarDecl added_global_var;
237   added_global_var.set_referenced_type(global_varp->GetReferencedType());
238   added_global_var.set_source_file(global_varp->GetSourceFile());
239   added_global_var.set_name(global_varp->GetName());
240   added_global_var.set_linker_set_key(global_varp->GetLinkerSetKey());
241   added_global_var.set_access(
242       AccessIRToProtobuf(global_varp->GetAccess()));
243   return added_global_var;
244 }
245 
ConvertPointerTypeIR(const PointerTypeIR * pointerp)246 abi_dump::PointerType IRToProtobufConverter::ConvertPointerTypeIR(
247     const PointerTypeIR *pointerp) {
248   abi_dump::PointerType added_pointer_type;
249   if (!AddTypeInfo(added_pointer_type.mutable_type_info(), pointerp)) {
250     llvm::errs() << "PointerTypeIR could not be converted\n";
251     ::exit(1);
252   }
253   return added_pointer_type;
254 }
255 
ConvertQualifiedTypeIR(const QualifiedTypeIR * qualtypep)256 abi_dump::QualifiedType IRToProtobufConverter::ConvertQualifiedTypeIR(
257     const QualifiedTypeIR *qualtypep) {
258   abi_dump::QualifiedType added_qualified_type;
259   if (!AddTypeInfo(added_qualified_type.mutable_type_info(), qualtypep)) {
260     llvm::errs() << "QualifiedTypeIR could not be converted\n";
261     ::exit(1);
262   }
263   added_qualified_type.set_is_const(qualtypep->IsConst());
264   added_qualified_type.set_is_volatile(qualtypep->IsVolatile());
265   added_qualified_type.set_is_restricted(qualtypep->IsRestricted());
266   return added_qualified_type;
267 }
268 
ConvertBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)269 abi_dump::BuiltinType IRToProtobufConverter::ConvertBuiltinTypeIR(
270     const BuiltinTypeIR *builtin_typep) {
271   abi_dump::BuiltinType added_builtin_type;
272   added_builtin_type.set_is_unsigned(builtin_typep->IsUnsigned());
273   added_builtin_type.set_is_integral(builtin_typep->IsIntegralType());
274   if (!AddTypeInfo(added_builtin_type.mutable_type_info(), builtin_typep)) {
275     llvm::errs() << "BuiltinTypeIR could not be converted\n";
276     ::exit(1);
277   }
278   return added_builtin_type;
279 }
280 
ConvertArrayTypeIR(const ArrayTypeIR * array_typep)281 abi_dump::ArrayType IRToProtobufConverter::ConvertArrayTypeIR(
282     const ArrayTypeIR *array_typep) {
283   abi_dump::ArrayType added_array_type;
284   if (!AddTypeInfo(added_array_type.mutable_type_info(), array_typep)) {
285     llvm::errs() << "ArrayTypeIR could not be converted\n";
286     ::exit(1);
287   }
288   return added_array_type;
289 }
290 
291 abi_dump::LvalueReferenceType
ConvertLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)292 IRToProtobufConverter::ConvertLvalueReferenceTypeIR(
293     const LvalueReferenceTypeIR *lvalue_reference_typep) {
294   abi_dump::LvalueReferenceType added_lvalue_reference_type;
295   if (!AddTypeInfo(added_lvalue_reference_type.mutable_type_info(),
296                    lvalue_reference_typep)) {
297     llvm::errs() << "LvalueReferenceTypeIR could not be converted\n";
298     ::exit(1);
299   }
300   return added_lvalue_reference_type;
301 }
302 
303 abi_dump::RvalueReferenceType
ConvertRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)304 IRToProtobufConverter::ConvertRvalueReferenceTypeIR(
305     const RvalueReferenceTypeIR *rvalue_reference_typep) {
306   abi_dump::RvalueReferenceType added_rvalue_reference_type;
307   if (!AddTypeInfo(added_rvalue_reference_type.mutable_type_info(),
308                    rvalue_reference_typep)) {
309     llvm::errs() << "RvalueReferenceTypeIR could not be converted\n";
310     ::exit(1);
311   }
312   return added_rvalue_reference_type;
313 }
314 
AddLinkableMessageIR(const LinkableMessageIR * lm)315 bool ProtobufIRDumper::AddLinkableMessageIR (const LinkableMessageIR *lm) {
316   // No RTTI
317   switch (lm->GetKind()) {
318     case RecordTypeKind:
319       return AddRecordTypeIR(static_cast<const RecordTypeIR *>(lm));
320     case EnumTypeKind:
321       return AddEnumTypeIR(static_cast<const EnumTypeIR *>(lm));
322     case PointerTypeKind:
323       return AddPointerTypeIR(static_cast<const PointerTypeIR *>(lm));
324     case QualifiedTypeKind:
325       return AddQualifiedTypeIR(static_cast<const QualifiedTypeIR *>(lm));
326     case ArrayTypeKind:
327       return AddArrayTypeIR(static_cast<const ArrayTypeIR *>(lm));
328     case LvalueReferenceTypeKind:
329       return AddLvalueReferenceTypeIR(
330           static_cast<const LvalueReferenceTypeIR *>(lm));
331     case RvalueReferenceTypeKind:
332       return AddRvalueReferenceTypeIR(
333           static_cast<const RvalueReferenceTypeIR*>(lm));
334     case BuiltinTypeKind:
335       return AddBuiltinTypeIR(static_cast<const BuiltinTypeIR*>(lm));
336     case FunctionTypeKind:
337       return AddFunctionTypeIR(static_cast<const FunctionTypeIR*>(lm));
338     case GlobalVarKind:
339       return AddGlobalVarIR(static_cast<const GlobalVarIR*>(lm));
340     case FunctionKind:
341       return AddFunctionIR(static_cast<const FunctionIR*>(lm));
342   }
343   return false;
344 }
345 
AddElfFunctionIR(const ElfFunctionIR * elf_function)346 bool ProtobufIRDumper::AddElfFunctionIR(const ElfFunctionIR *elf_function) {
347   abi_dump::ElfFunction *added_elf_function = tu_ptr_->add_elf_functions();
348   if (!added_elf_function) {
349     return false;
350   }
351   added_elf_function->set_name(elf_function->GetName());
352   added_elf_function->set_binding(
353       ElfSymbolBindingIRToProtobuf(elf_function->GetBinding()));
354   return true;
355 }
356 
AddElfObjectIR(const ElfObjectIR * elf_object)357 bool ProtobufIRDumper::AddElfObjectIR(const ElfObjectIR *elf_object) {
358   abi_dump::ElfObject *added_elf_object = tu_ptr_->add_elf_objects();
359   if (!added_elf_object) {
360     return false;
361   }
362   added_elf_object->set_name(elf_object->GetName());
363   added_elf_object->set_binding(
364       ElfSymbolBindingIRToProtobuf(elf_object->GetBinding()));
365   return true;
366 }
367 
AddElfSymbolMessageIR(const ElfSymbolIR * em)368 bool ProtobufIRDumper::AddElfSymbolMessageIR(const ElfSymbolIR *em) {
369   switch (em->GetKind()) {
370     case ElfSymbolIR::ElfFunctionKind:
371       return AddElfFunctionIR(static_cast<const ElfFunctionIR *>(em));
372     case ElfSymbolIR::ElfObjectKind:
373       return AddElfObjectIR(static_cast<const ElfObjectIR *>(em));
374   }
375   return false;
376 }
377 
AddRecordTypeIR(const RecordTypeIR * recordp)378 bool ProtobufIRDumper::AddRecordTypeIR(const RecordTypeIR *recordp) {
379   abi_dump::RecordType *added_record_type = tu_ptr_->add_record_types();
380   if (!added_record_type) {
381     return false;
382   }
383   *added_record_type = ConvertRecordTypeIR(recordp);
384   return true;
385 }
386 
AddFunctionTypeIR(const FunctionTypeIR * function_typep)387 bool ProtobufIRDumper::AddFunctionTypeIR(const FunctionTypeIR *function_typep) {
388   abi_dump::FunctionType *added_function_type = tu_ptr_->add_function_types();
389   if (!added_function_type) {
390     return false;
391   }
392   *added_function_type = ConvertFunctionTypeIR(function_typep);
393   return true;
394 }
395 
AddFunctionIR(const FunctionIR * functionp)396 bool ProtobufIRDumper::AddFunctionIR(const FunctionIR *functionp) {
397   abi_dump::FunctionDecl *added_function = tu_ptr_->add_functions();
398   if (!added_function) {
399     return false;
400   }
401   *added_function = ConvertFunctionIR(functionp);
402   return true;
403 }
404 
AddEnumTypeIR(const EnumTypeIR * enump)405 bool ProtobufIRDumper::AddEnumTypeIR(const EnumTypeIR *enump) {
406   abi_dump::EnumType *added_enum_type = tu_ptr_->add_enum_types();
407   if (!added_enum_type) {
408     return false;
409   }
410   *added_enum_type = ConvertEnumTypeIR(enump);
411   return true;
412 }
413 
AddGlobalVarIR(const GlobalVarIR * global_varp)414 bool ProtobufIRDumper::AddGlobalVarIR(const GlobalVarIR *global_varp) {
415   abi_dump::GlobalVarDecl *added_global_var = tu_ptr_->add_global_vars();
416   if (!added_global_var) {
417     return false;
418   }
419   *added_global_var = ConvertGlobalVarIR(global_varp);
420   return true;
421 }
422 
AddPointerTypeIR(const PointerTypeIR * pointerp)423 bool ProtobufIRDumper::AddPointerTypeIR(const PointerTypeIR *pointerp) {
424   abi_dump::PointerType *added_pointer_type = tu_ptr_->add_pointer_types();
425   if (!added_pointer_type) {
426     return false;
427   }
428   *added_pointer_type = ConvertPointerTypeIR(pointerp);
429   return true;
430 }
431 
AddQualifiedTypeIR(const QualifiedTypeIR * qualtypep)432 bool ProtobufIRDumper::AddQualifiedTypeIR(const QualifiedTypeIR *qualtypep) {
433   abi_dump::QualifiedType *added_qualified_type =
434       tu_ptr_->add_qualified_types();
435   if (!added_qualified_type) {
436     return false;
437   }
438   *added_qualified_type = ConvertQualifiedTypeIR(qualtypep);
439   return true;
440 }
441 
AddBuiltinTypeIR(const BuiltinTypeIR * builtin_typep)442 bool ProtobufIRDumper::AddBuiltinTypeIR(const BuiltinTypeIR *builtin_typep) {
443   abi_dump::BuiltinType *added_builtin_type =
444       tu_ptr_->add_builtin_types();
445   if (!added_builtin_type) {
446     return false;
447   }
448   *added_builtin_type = ConvertBuiltinTypeIR(builtin_typep);
449   return true;
450 }
451 
AddArrayTypeIR(const ArrayTypeIR * array_typep)452 bool ProtobufIRDumper::AddArrayTypeIR(const ArrayTypeIR *array_typep) {
453   abi_dump::ArrayType *added_array_type =
454       tu_ptr_->add_array_types();
455   if (!added_array_type) {
456     return false;
457   }
458   *added_array_type = ConvertArrayTypeIR(array_typep);
459   return true;
460 }
461 
AddLvalueReferenceTypeIR(const LvalueReferenceTypeIR * lvalue_reference_typep)462 bool ProtobufIRDumper::AddLvalueReferenceTypeIR(
463     const LvalueReferenceTypeIR *lvalue_reference_typep) {
464   abi_dump::LvalueReferenceType *added_lvalue_reference_type =
465       tu_ptr_->add_lvalue_reference_types();
466   if (!added_lvalue_reference_type) {
467     return false;
468   }
469   *added_lvalue_reference_type =
470       ConvertLvalueReferenceTypeIR(lvalue_reference_typep);
471   return true;
472 }
473 
AddRvalueReferenceTypeIR(const RvalueReferenceTypeIR * rvalue_reference_typep)474 bool ProtobufIRDumper::AddRvalueReferenceTypeIR(
475     const RvalueReferenceTypeIR *rvalue_reference_typep) {
476   abi_dump::RvalueReferenceType *added_rvalue_reference_type =
477       tu_ptr_->add_rvalue_reference_types();
478   if (!added_rvalue_reference_type) {
479     return false;
480   }
481   *added_rvalue_reference_type =
482       ConvertRvalueReferenceTypeIR(rvalue_reference_typep);
483   return true;
484 }
485 
Dump(const ModuleIR & module)486 bool ProtobufIRDumper::Dump(const ModuleIR &module) {
487   GOOGLE_PROTOBUF_VERIFY_VERSION;
488   DumpModule(module);
489   assert( tu_ptr_.get() != nullptr);
490   std::ofstream text_output(dump_path_);
491   google::protobuf::io::OstreamOutputStream text_os(&text_output);
492   return google::protobuf::TextFormat::Print(*tu_ptr_.get(), &text_os);
493 }
494 
CreateProtobufIRDumper(const std::string & dump_path)495 std::unique_ptr<IRDumper> CreateProtobufIRDumper(const std::string &dump_path) {
496   return std::make_unique<ProtobufIRDumper>(dump_path);
497 }
498 
499 
500 }  // namespace repr
501 }  // namespace header_checker
502