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: 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,84 @@ 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}); + + static llvm::DenseMap Types; + if (Types.empty()) { + Types[getContext().CharTy] = "%c"; + Types[getContext().BoolTy] = "%d"; + Types[getContext().IntTy] = "%d"; + Types[getContext().UnsignedIntTy] = "%u"; + Types[getContext().LongTy] = "%ld"; + Types[getContext().UnsignedLongTy] = "%lu"; + Types[getContext().LongLongTy] = "%lld"; + Types[getContext().UnsignedLongLongTy] = "%llu"; + Types[getContext().ShortTy] = "%hd"; + Types[getContext().UnsignedShortTy] = "%hu"; + Types[getContext().VoidPtrTy] = "%p"; + Types[getContext().FloatTy] = "%f"; + Types[getContext().DoubleTy] = "%f"; + Types[getContext().LongDoubleTy] = "%Lf"; + Types[getContext().getPointerType(getContext().CharTy)] = "%s"; + } + + 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 + + QualType CanonicalType = + FD->getType().getUnqualifiedType().getCanonicalType(); + if (Types.find(CanonicalType) == Types.end()) + Format += Types[getContext().VoidPtrTy]; + else + Format += Types[CanonicalType]; + + 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); + + // FIXME 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,66 @@ // so ensure that they are declared. DeclareGlobalNewDelete(); break; + case Builtin::BI__builtin_dump_struct: { + // We first want to ensure we are called with 2 arguments + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + // Ensure that the first argument is of type 'struct XX *' + const Expr *PtrArg = TheCall->getArg(0)->IgnoreParenImpCasts(); + const QualType PtrArgType = PtrArg->getType(); + if (!PtrArgType->isPointerType()) { + this->Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "\'structure pointer type\'" + << 1 << 0 << 3 << 1 + << PtrArgType << "\'structure pointer type\'"; + return ExprError(); + } + + const RecordType *RT = PtrArgType->getPointeeType()->getAs(); + if (!RT) { + this->Diag(PtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << PtrArgType << "\'structure pointer type\'" + << 1 << 0 << 3 << 1 + << PtrArgType << "\'structure pointer type\'"; + return ExprError(); + } + // Ensure that the second argument is of type 'FunctionType' + const Expr *FnPtrArg = TheCall->getArg(1)->IgnoreImpCasts(); + const QualType FnPtrArgType = FnPtrArg->getType(); + if (!FnPtrArgType->isPointerType()) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + + const FunctionType *FuncType = + FnPtrArgType->getPointeeType()->getAs(); + + if (!FuncType) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType << "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + + const FunctionProtoType *FT = dyn_cast(FuncType); + if (FT) { + if (!FT->isVariadic() || + FT->getReturnType() != Context.IntTy) { + this->Diag(FnPtrArg->getLocStart(), diag::err_typecheck_convert_incompatible) + << FnPtrArgType<< "\'int (*)(const char *, ...)\'" + << 1 << 0 << 3 << 2 + << FnPtrArgType << "\'int (*)(const char *, ...)\'"; + return ExprError(); + } + } + + TheCall->setType(Context.IntTy); + break; + } // check secure string manipulation functions where overflows // are detectable at compile time