Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1374,6 +1374,7 @@ BUILTIN(__builtin_operator_new, "v*z", "c") BUILTIN(__builtin_operator_delete, "vv*", "n") BUILTIN(__builtin_char_memchr, "c*cC*iz", "n") +BUILTIN(__builtin_dump_struct, "ivC*v*", "tn") // Safestack builtins BUILTIN(__builtin___get_unsafe_stack_start, "v*", "Fn") Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -5019,6 +5019,9 @@ def err_incorrect_number_of_vector_initializers : Error< "number of elements must be either one or match the size of the vector">; +def err_dump_struct_invalid_argument_type : Error< + "invalid argument of type %0; expected %1">; + // Used by C++ which allows bit-fields that are wider than the type. def warn_bitfield_width_exceeds_type_width: Warning< "width of bit-field %0 (%1 bits) exceeds the width of its type; value will " Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -14,6 +14,7 @@ #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -1196,6 +1197,103 @@ return RValue::get(ComplexVal.first); } + case Builtin::BI__builtin_dump_struct: { + Value *Func = EmitScalarExpr(E->getArg(1)->IgnoreImpCasts()); + CharUnits Arg0Align = EmitPointerWithAlignment(E->getArg(0)).getAlignment(); + + const Expr *Arg0 = E->getArg(0)->IgnoreImpCasts(); + QualType Arg0Type = Arg0->getType()->getPointeeType(); + const RecordType *RT = Arg0Type->getAs(); + + RecordDecl *RD = RT->getDecl()->getDefinition(); + ASTContext &Ctx = RD->getASTContext(); + const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD); + + Value *GString = Builder.CreateGlobalStringPtr(Arg0Type.getAsString() + + " {\n"); + Value *Res = Builder.CreateCall(Func, {GString}); + +#define GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(type, format) \ + Types[getContext().getConstType(type)] = format; \ + Types[getContext().getVolatileType(type)] = format; \ + Types[getContext().getConstType(getContext().getVolatileType(type))] = format; + + static llvm::DenseMap Types; + if (Types.empty()) { + Types[getContext().CharTy] = "%c"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().CharTy, "%c") + Types[getContext().BoolTy] = "%d"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().BoolTy, "%d") + Types[getContext().IntTy] = "%d"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().IntTy, "%d") + Types[getContext().UnsignedIntTy] = "%u"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().UnsignedIntTy, "%u") + Types[getContext().LongTy] = "%ld"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().LongTy, "%ld") + Types[getContext().UnsignedLongTy] = "%lu"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().UnsignedLongTy, "%lu") + Types[getContext().LongLongTy] = "%lld"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().LongLongTy, "%lld") + Types[getContext().UnsignedLongLongTy] = "%llu"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().UnsignedLongLongTy, "%llu") + Types[getContext().ShortTy] = "%hd"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().ShortTy, "%hd") + Types[getContext().UnsignedShortTy] = "%hu"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().UnsignedShortTy, "%hu") + Types[getContext().VoidPtrTy] = "%p"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().VoidPtrTy, "%p") + Types[getContext().FloatTy] = "%f"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().FloatTy, "%f") + Types[getContext().DoubleTy] = "%f"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().DoubleTy, "%f") + Types[getContext().LongDoubleTy] = "%Lf"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().LongDoubleTy, "%Lf") + Types[getContext().getPointerType(getContext().CharTy)] = "%s"; + GENERATE_TYPE_QUALIFIERS_NO_RESTRICT(getContext().CharTy, "%s") + } + + /* field : RecordDecl::field_iterator */ + for (const auto *FD : RD->fields()) { + uint64_t Off = RL.getFieldOffset(FD->getFieldIndex()); + Off = Ctx.toCharUnitsFromBits(Off).getQuantity(); + + Value *FieldPtr = EmitScalarExpr(E->getArg(0)); + if (Off) { + FieldPtr = Builder.CreatePtrToInt(FieldPtr, IntPtrTy); + FieldPtr = Builder.CreateAdd(FieldPtr, ConstantInt::get(IntPtrTy, Off)); + FieldPtr = Builder.CreateIntToPtr(FieldPtr, VoidPtrTy); + } + std::string Format = FD->getType().getAsString() + std::string(" ") + + FD->getNameAsString() + " : "; + + /* If the type is not handled yet, let's just print the data as a pointer + */ + if (Types.find(FD->getType()) == Types.end()) + Format += Types[getContext().VoidPtrTy]; + else + Format += Types[FD->getType()]; + + QualType ResPtrType = getContext().getPointerType(FD->getType()); + llvm::Type *ResType = ConvertType(ResPtrType); + FieldPtr = Builder.CreatePointerCast(FieldPtr, ResType); + Address FieldAddress = Address(FieldPtr, Arg0Align); + FieldPtr = Builder.CreateLoad(FieldAddress); + + // Need to handle bitfield here + + GString = Builder.CreateGlobalStringPtr(Format + "\n"); + Value *TmpRes = Builder.CreateCall(Func, {GString, FieldPtr}); + Res = Builder.CreateAdd(Res, TmpRes); + } + + std::string Format = "}\n"; + GString = Builder.CreateGlobalStringPtr(Format); + Value *TmpRes = Builder.CreateCall(Func, {GString}); + Res = Builder.CreateAdd(Res, TmpRes); + + return RValue::get(Res); + } + case Builtin::BI__builtin_cimag: case Builtin::BI__builtin_cimagf: case Builtin::BI__builtin_cimagl: Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1110,6 +1110,53 @@ // so ensure that they are declared. DeclareGlobalNewDelete(); break; + case Builtin::BI__builtin_dump_struct: { + // We check for argument number + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *Arg0 = TheCall->getArg(0)->IgnoreImpCasts(); + if (!Arg0->getType()->isPointerType()) { + this->Diag(Arg0->getLocStart(), diag::err_dump_struct_invalid_argument_type) + << Arg0->getType() << "structure pointer type"; + return ExprError(); + } + QualType Arg0Type = Arg0->getType()->getPointeeType(); + const RecordType *RT = Arg0Type->getAs(); + if (!RT) { + this->Diag(Arg0->getLocStart(), diag::err_dump_struct_invalid_argument_type) + << Arg0->getType() << "structure pointer type"; + return ExprError(); + } + // Ensure that the second argument is of type 'FunctionType' + const Expr *Arg1 = TheCall->getArg(1)->IgnoreImpCasts(); + if (!Arg1->getType()->isPointerType()) { + this->Diag(Arg1->getLocStart(), diag::err_dump_struct_invalid_argument_type) + << Arg1->getType() << "printf like function pointer type"; + return ExprError(); + } + + const FunctionType *FuncType = Arg1->getType()->getPointeeType()->getAs(); + + if (!FuncType) { + this->Diag(Arg1->getLocStart(), diag::err_dump_struct_invalid_argument_type) + << Arg1->getType() << "printf like function pointer type"; + return ExprError(); + } + + const FunctionProtoType *FT = dyn_cast(FuncType); + if (FT) { + if (!FT->isVariadic()) { + this->Diag(Arg1->getLocStart(), diag::err_dump_struct_invalid_argument_type) + << Arg1->getType() << "printf like function pointer type"; + return ExprError(); + } + } + + + TheCall->setType(Context.IntTy); + break; + } // check secure string manipulation functions where overflows // are detectable at compile time