1 1.1 joerg // TODO: header template 2 1.1 joerg 3 1.1 joerg #include "clang/AST/OSLog.h" 4 1.1 joerg #include "clang/AST/Attr.h" 5 1.1 joerg #include "clang/AST/Decl.h" 6 1.1 joerg #include "clang/AST/DeclCXX.h" 7 1.1 joerg #include "clang/AST/ExprObjC.h" 8 1.1 joerg #include "clang/AST/FormatString.h" 9 1.1 joerg #include "clang/Basic/Builtins.h" 10 1.1 joerg #include "llvm/ADT/SmallBitVector.h" 11 1.1 joerg 12 1.1 joerg using namespace clang; 13 1.1 joerg 14 1.1 joerg using clang::analyze_os_log::OSLogBufferItem; 15 1.1 joerg using clang::analyze_os_log::OSLogBufferLayout; 16 1.1 joerg 17 1.1 joerg namespace { 18 1.1 joerg class OSLogFormatStringHandler 19 1.1 joerg : public analyze_format_string::FormatStringHandler { 20 1.1 joerg private: 21 1.1 joerg struct ArgData { 22 1.1 joerg const Expr *E = nullptr; 23 1.1 joerg Optional<OSLogBufferItem::Kind> Kind; 24 1.1 joerg Optional<unsigned> Size; 25 1.1 joerg Optional<const Expr *> Count; 26 1.1 joerg Optional<const Expr *> Precision; 27 1.1 joerg Optional<const Expr *> FieldWidth; 28 1.1 joerg unsigned char Flags = 0; 29 1.1 joerg StringRef MaskType; 30 1.1 joerg }; 31 1.1 joerg SmallVector<ArgData, 4> ArgsData; 32 1.1 joerg ArrayRef<const Expr *> Args; 33 1.1 joerg 34 1.1 joerg OSLogBufferItem::Kind 35 1.1 joerg getKind(analyze_format_string::ConversionSpecifier::Kind K) { 36 1.1 joerg switch (K) { 37 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s" 38 1.1 joerg return OSLogBufferItem::StringKind; 39 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S" 40 1.1 joerg return OSLogBufferItem::WideStringKind; 41 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P" 42 1.1 joerg return OSLogBufferItem::PointerKind; 43 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@" 44 1.1 joerg return OSLogBufferItem::ObjCObjKind; 45 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m" 46 1.1 joerg return OSLogBufferItem::ErrnoKind; 47 1.1 joerg default: 48 1.1 joerg return OSLogBufferItem::ScalarKind; 49 1.1 joerg } 50 1.1 joerg } 51 1.1 joerg } 52 1.1 joerg 53 1.1 joerg public: 54 1.1 joerg OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) { 55 1.1 joerg ArgsData.reserve(Args.size()); 56 1.1 joerg } 57 1.1 joerg 58 1.1.1.2 joerg bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, 59 1.1.1.2 joerg const char *StartSpecifier, 60 1.1.1.2 joerg unsigned SpecifierLen) override { 61 1.1 joerg if (!FS.consumesDataArgument() && 62 1.1 joerg FS.getConversionSpecifier().getKind() != 63 1.1 joerg clang::analyze_format_string::ConversionSpecifier::PrintErrno) 64 1.1 joerg return true; 65 1.1 joerg 66 1.1 joerg ArgsData.emplace_back(); 67 1.1 joerg unsigned ArgIndex = FS.getArgIndex(); 68 1.1 joerg if (ArgIndex < Args.size()) 69 1.1 joerg ArgsData.back().E = Args[ArgIndex]; 70 1.1 joerg 71 1.1 joerg // First get the Kind 72 1.1 joerg ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind()); 73 1.1 joerg if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind && 74 1.1 joerg !ArgsData.back().E) { 75 1.1 joerg // missing argument 76 1.1 joerg ArgsData.pop_back(); 77 1.1 joerg return false; 78 1.1 joerg } 79 1.1 joerg 80 1.1 joerg switch (FS.getConversionSpecifier().getKind()) { 81 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s" 82 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S" 83 1.1 joerg auto &precision = FS.getPrecision(); 84 1.1 joerg switch (precision.getHowSpecified()) { 85 1.1 joerg case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s" 86 1.1 joerg break; 87 1.1 joerg case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s" 88 1.1 joerg ArgsData.back().Size = precision.getConstantAmount(); 89 1.1 joerg break; 90 1.1 joerg case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s" 91 1.1 joerg ArgsData.back().Count = Args[precision.getArgIndex()]; 92 1.1 joerg break; 93 1.1 joerg case clang::analyze_format_string::OptionalAmount::Invalid: 94 1.1 joerg return false; 95 1.1 joerg } 96 1.1 joerg break; 97 1.1 joerg } 98 1.1 joerg case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P" 99 1.1 joerg auto &precision = FS.getPrecision(); 100 1.1 joerg switch (precision.getHowSpecified()) { 101 1.1 joerg case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P" 102 1.1 joerg return false; // length must be supplied with pointer format specifier 103 1.1 joerg case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P" 104 1.1 joerg ArgsData.back().Size = precision.getConstantAmount(); 105 1.1 joerg break; 106 1.1 joerg case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P" 107 1.1 joerg ArgsData.back().Count = Args[precision.getArgIndex()]; 108 1.1 joerg break; 109 1.1 joerg case clang::analyze_format_string::OptionalAmount::Invalid: 110 1.1 joerg return false; 111 1.1 joerg } 112 1.1 joerg break; 113 1.1 joerg } 114 1.1 joerg default: 115 1.1 joerg if (FS.getPrecision().hasDataArgument()) { 116 1.1 joerg ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()]; 117 1.1 joerg } 118 1.1 joerg break; 119 1.1 joerg } 120 1.1 joerg if (FS.getFieldWidth().hasDataArgument()) { 121 1.1 joerg ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()]; 122 1.1 joerg } 123 1.1 joerg 124 1.1 joerg if (FS.isSensitive()) 125 1.1 joerg ArgsData.back().Flags |= OSLogBufferItem::IsSensitive; 126 1.1 joerg else if (FS.isPrivate()) 127 1.1 joerg ArgsData.back().Flags |= OSLogBufferItem::IsPrivate; 128 1.1 joerg else if (FS.isPublic()) 129 1.1 joerg ArgsData.back().Flags |= OSLogBufferItem::IsPublic; 130 1.1 joerg 131 1.1 joerg ArgsData.back().MaskType = FS.getMaskType(); 132 1.1 joerg return true; 133 1.1 joerg } 134 1.1 joerg 135 1.1 joerg void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const { 136 1.1 joerg Layout.Items.clear(); 137 1.1 joerg for (auto &Data : ArgsData) { 138 1.1 joerg if (!Data.MaskType.empty()) { 139 1.1 joerg CharUnits Size = CharUnits::fromQuantity(8); 140 1.1 joerg Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr, 141 1.1 joerg Size, 0, Data.MaskType); 142 1.1 joerg } 143 1.1 joerg 144 1.1 joerg if (Data.FieldWidth) { 145 1.1 joerg CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType()); 146 1.1 joerg Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth, 147 1.1 joerg Size, 0); 148 1.1 joerg } 149 1.1 joerg if (Data.Precision) { 150 1.1 joerg CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType()); 151 1.1 joerg Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision, 152 1.1 joerg Size, 0); 153 1.1 joerg } 154 1.1 joerg if (Data.Count) { 155 1.1 joerg // "%.*P" has an extra "count" that we insert before the argument. 156 1.1 joerg CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType()); 157 1.1 joerg Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size, 158 1.1 joerg 0); 159 1.1 joerg } 160 1.1 joerg if (Data.Size) 161 1.1 joerg Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size), 162 1.1 joerg Data.Flags); 163 1.1 joerg if (Data.Kind) { 164 1.1 joerg CharUnits Size; 165 1.1 joerg if (*Data.Kind == OSLogBufferItem::ErrnoKind) 166 1.1 joerg Size = CharUnits::Zero(); 167 1.1 joerg else 168 1.1 joerg Size = Ctx.getTypeSizeInChars(Data.E->getType()); 169 1.1 joerg Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags); 170 1.1 joerg } else { 171 1.1 joerg auto Size = Ctx.getTypeSizeInChars(Data.E->getType()); 172 1.1 joerg Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size, 173 1.1 joerg Data.Flags); 174 1.1 joerg } 175 1.1 joerg } 176 1.1 joerg } 177 1.1 joerg }; 178 1.1 joerg } // end anonymous namespace 179 1.1 joerg 180 1.1 joerg bool clang::analyze_os_log::computeOSLogBufferLayout( 181 1.1 joerg ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) { 182 1.1 joerg ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs()); 183 1.1 joerg 184 1.1 joerg const Expr *StringArg; 185 1.1 joerg ArrayRef<const Expr *> VarArgs; 186 1.1 joerg switch (E->getBuiltinCallee()) { 187 1.1 joerg case Builtin::BI__builtin_os_log_format_buffer_size: 188 1.1 joerg assert(E->getNumArgs() >= 1 && 189 1.1 joerg "__builtin_os_log_format_buffer_size takes at least 1 argument"); 190 1.1 joerg StringArg = E->getArg(0); 191 1.1 joerg VarArgs = Args.slice(1); 192 1.1 joerg break; 193 1.1 joerg case Builtin::BI__builtin_os_log_format: 194 1.1 joerg assert(E->getNumArgs() >= 2 && 195 1.1 joerg "__builtin_os_log_format takes at least 2 arguments"); 196 1.1 joerg StringArg = E->getArg(1); 197 1.1 joerg VarArgs = Args.slice(2); 198 1.1 joerg break; 199 1.1 joerg default: 200 1.1 joerg llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout"); 201 1.1 joerg } 202 1.1 joerg 203 1.1 joerg const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts()); 204 1.1 joerg assert(Lit && (Lit->isAscii() || Lit->isUTF8())); 205 1.1 joerg StringRef Data = Lit->getString(); 206 1.1 joerg OSLogFormatStringHandler H(VarArgs); 207 1.1 joerg ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(), 208 1.1 joerg Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false); 209 1.1 joerg 210 1.1 joerg H.computeLayout(Ctx, Layout); 211 1.1 joerg return true; 212 1.1 joerg } 213