10b57cec5SDimitry Andric // TODO: header template 20b57cec5SDimitry Andric 30b57cec5SDimitry Andric #include "clang/AST/OSLog.h" 40b57cec5SDimitry Andric #include "clang/AST/Attr.h" 50b57cec5SDimitry Andric #include "clang/AST/Decl.h" 60b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 70b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h" 80b57cec5SDimitry Andric #include "clang/AST/FormatString.h" 90b57cec5SDimitry Andric #include "clang/Basic/Builtins.h" 100b57cec5SDimitry Andric #include "llvm/ADT/SmallBitVector.h" 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric using namespace clang; 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric using clang::analyze_os_log::OSLogBufferItem; 150b57cec5SDimitry Andric using clang::analyze_os_log::OSLogBufferLayout; 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric namespace { 180b57cec5SDimitry Andric class OSLogFormatStringHandler 190b57cec5SDimitry Andric : public analyze_format_string::FormatStringHandler { 200b57cec5SDimitry Andric private: 210b57cec5SDimitry Andric struct ArgData { 220b57cec5SDimitry Andric const Expr *E = nullptr; 230b57cec5SDimitry Andric Optional<OSLogBufferItem::Kind> Kind; 240b57cec5SDimitry Andric Optional<unsigned> Size; 250b57cec5SDimitry Andric Optional<const Expr *> Count; 260b57cec5SDimitry Andric Optional<const Expr *> Precision; 270b57cec5SDimitry Andric Optional<const Expr *> FieldWidth; 280b57cec5SDimitry Andric unsigned char Flags = 0; 290b57cec5SDimitry Andric StringRef MaskType; 300b57cec5SDimitry Andric }; 310b57cec5SDimitry Andric SmallVector<ArgData, 4> ArgsData; 320b57cec5SDimitry Andric ArrayRef<const Expr *> Args; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric OSLogBufferItem::Kind 350b57cec5SDimitry Andric getKind(analyze_format_string::ConversionSpecifier::Kind K) { 360b57cec5SDimitry Andric switch (K) { 370b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s" 380b57cec5SDimitry Andric return OSLogBufferItem::StringKind; 390b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S" 400b57cec5SDimitry Andric return OSLogBufferItem::WideStringKind; 410b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P" 420b57cec5SDimitry Andric return OSLogBufferItem::PointerKind; 430b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@" 440b57cec5SDimitry Andric return OSLogBufferItem::ObjCObjKind; 450b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m" 460b57cec5SDimitry Andric return OSLogBufferItem::ErrnoKind; 470b57cec5SDimitry Andric default: 480b57cec5SDimitry Andric return OSLogBufferItem::ScalarKind; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric } 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric public: 540b57cec5SDimitry Andric OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) { 550b57cec5SDimitry Andric ArgsData.reserve(Args.size()); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 58*5ffd83dbSDimitry Andric bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 590b57cec5SDimitry Andric const char *StartSpecifier, 60*5ffd83dbSDimitry Andric unsigned SpecifierLen) override { 610b57cec5SDimitry Andric if (!FS.consumesDataArgument() && 620b57cec5SDimitry Andric FS.getConversionSpecifier().getKind() != 630b57cec5SDimitry Andric clang::analyze_format_string::ConversionSpecifier::PrintErrno) 640b57cec5SDimitry Andric return true; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric ArgsData.emplace_back(); 670b57cec5SDimitry Andric unsigned ArgIndex = FS.getArgIndex(); 680b57cec5SDimitry Andric if (ArgIndex < Args.size()) 690b57cec5SDimitry Andric ArgsData.back().E = Args[ArgIndex]; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // First get the Kind 720b57cec5SDimitry Andric ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind()); 730b57cec5SDimitry Andric if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind && 740b57cec5SDimitry Andric !ArgsData.back().E) { 750b57cec5SDimitry Andric // missing argument 760b57cec5SDimitry Andric ArgsData.pop_back(); 770b57cec5SDimitry Andric return false; 780b57cec5SDimitry Andric } 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric switch (FS.getConversionSpecifier().getKind()) { 810b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s" 820b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S" 830b57cec5SDimitry Andric auto &precision = FS.getPrecision(); 840b57cec5SDimitry Andric switch (precision.getHowSpecified()) { 850b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s" 860b57cec5SDimitry Andric break; 870b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s" 880b57cec5SDimitry Andric ArgsData.back().Size = precision.getConstantAmount(); 890b57cec5SDimitry Andric break; 900b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s" 910b57cec5SDimitry Andric ArgsData.back().Count = Args[precision.getArgIndex()]; 920b57cec5SDimitry Andric break; 930b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Invalid: 940b57cec5SDimitry Andric return false; 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric break; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P" 990b57cec5SDimitry Andric auto &precision = FS.getPrecision(); 1000b57cec5SDimitry Andric switch (precision.getHowSpecified()) { 1010b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P" 1020b57cec5SDimitry Andric return false; // length must be supplied with pointer format specifier 1030b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P" 1040b57cec5SDimitry Andric ArgsData.back().Size = precision.getConstantAmount(); 1050b57cec5SDimitry Andric break; 1060b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P" 1070b57cec5SDimitry Andric ArgsData.back().Count = Args[precision.getArgIndex()]; 1080b57cec5SDimitry Andric break; 1090b57cec5SDimitry Andric case clang::analyze_format_string::OptionalAmount::Invalid: 1100b57cec5SDimitry Andric return false; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric break; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric default: 1150b57cec5SDimitry Andric if (FS.getPrecision().hasDataArgument()) { 1160b57cec5SDimitry Andric ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()]; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric break; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric if (FS.getFieldWidth().hasDataArgument()) { 1210b57cec5SDimitry Andric ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()]; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric if (FS.isSensitive()) 1250b57cec5SDimitry Andric ArgsData.back().Flags |= OSLogBufferItem::IsSensitive; 1260b57cec5SDimitry Andric else if (FS.isPrivate()) 1270b57cec5SDimitry Andric ArgsData.back().Flags |= OSLogBufferItem::IsPrivate; 1280b57cec5SDimitry Andric else if (FS.isPublic()) 1290b57cec5SDimitry Andric ArgsData.back().Flags |= OSLogBufferItem::IsPublic; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric ArgsData.back().MaskType = FS.getMaskType(); 1320b57cec5SDimitry Andric return true; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const { 1360b57cec5SDimitry Andric Layout.Items.clear(); 1370b57cec5SDimitry Andric for (auto &Data : ArgsData) { 1380b57cec5SDimitry Andric if (!Data.MaskType.empty()) { 1390b57cec5SDimitry Andric CharUnits Size = CharUnits::fromQuantity(8); 1400b57cec5SDimitry Andric Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr, 1410b57cec5SDimitry Andric Size, 0, Data.MaskType); 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric if (Data.FieldWidth) { 1450b57cec5SDimitry Andric CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType()); 1460b57cec5SDimitry Andric Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth, 1470b57cec5SDimitry Andric Size, 0); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric if (Data.Precision) { 1500b57cec5SDimitry Andric CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType()); 1510b57cec5SDimitry Andric Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision, 1520b57cec5SDimitry Andric Size, 0); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric if (Data.Count) { 1550b57cec5SDimitry Andric // "%.*P" has an extra "count" that we insert before the argument. 1560b57cec5SDimitry Andric CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType()); 1570b57cec5SDimitry Andric Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size, 1580b57cec5SDimitry Andric 0); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric if (Data.Size) 1610b57cec5SDimitry Andric Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size), 1620b57cec5SDimitry Andric Data.Flags); 1630b57cec5SDimitry Andric if (Data.Kind) { 1640b57cec5SDimitry Andric CharUnits Size; 1650b57cec5SDimitry Andric if (*Data.Kind == OSLogBufferItem::ErrnoKind) 1660b57cec5SDimitry Andric Size = CharUnits::Zero(); 1670b57cec5SDimitry Andric else 1680b57cec5SDimitry Andric Size = Ctx.getTypeSizeInChars(Data.E->getType()); 1690b57cec5SDimitry Andric Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags); 1700b57cec5SDimitry Andric } else { 1710b57cec5SDimitry Andric auto Size = Ctx.getTypeSizeInChars(Data.E->getType()); 1720b57cec5SDimitry Andric Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size, 1730b57cec5SDimitry Andric Data.Flags); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric }; 1780b57cec5SDimitry Andric } // end anonymous namespace 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric bool clang::analyze_os_log::computeOSLogBufferLayout( 1810b57cec5SDimitry Andric ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) { 1820b57cec5SDimitry Andric ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs()); 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric const Expr *StringArg; 1850b57cec5SDimitry Andric ArrayRef<const Expr *> VarArgs; 1860b57cec5SDimitry Andric switch (E->getBuiltinCallee()) { 1870b57cec5SDimitry Andric case Builtin::BI__builtin_os_log_format_buffer_size: 1880b57cec5SDimitry Andric assert(E->getNumArgs() >= 1 && 1890b57cec5SDimitry Andric "__builtin_os_log_format_buffer_size takes at least 1 argument"); 1900b57cec5SDimitry Andric StringArg = E->getArg(0); 1910b57cec5SDimitry Andric VarArgs = Args.slice(1); 1920b57cec5SDimitry Andric break; 1930b57cec5SDimitry Andric case Builtin::BI__builtin_os_log_format: 1940b57cec5SDimitry Andric assert(E->getNumArgs() >= 2 && 1950b57cec5SDimitry Andric "__builtin_os_log_format takes at least 2 arguments"); 1960b57cec5SDimitry Andric StringArg = E->getArg(1); 1970b57cec5SDimitry Andric VarArgs = Args.slice(2); 1980b57cec5SDimitry Andric break; 1990b57cec5SDimitry Andric default: 2000b57cec5SDimitry Andric llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout"); 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts()); 2040b57cec5SDimitry Andric assert(Lit && (Lit->isAscii() || Lit->isUTF8())); 2050b57cec5SDimitry Andric StringRef Data = Lit->getString(); 2060b57cec5SDimitry Andric OSLogFormatStringHandler H(VarArgs); 2070b57cec5SDimitry Andric ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(), 2080b57cec5SDimitry Andric Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric H.computeLayout(Ctx, Layout); 2110b57cec5SDimitry Andric return true; 2120b57cec5SDimitry Andric } 213