OSLog.cpp revision 1.1.1.1.4.1 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.1.4.1 cjep bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
59 1.1.1.1.4.1 cjep const char *StartSpecifier,
60 1.1.1.1.4.1 cjep 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