clang  6.0.0svn
OSLog.cpp
Go to the documentation of this file.
1 // TODO: header template
2 
4 #include "clang/AST/Attr.h"
5 #include "clang/AST/Decl.h"
6 #include "clang/AST/DeclCXX.h"
7 #include "clang/AST/ExprObjC.h"
9 #include "clang/Basic/Builtins.h"
10 #include "llvm/ADT/SmallBitVector.h"
11 
12 using namespace clang;
13 
16 
17 namespace {
18 class OSLogFormatStringHandler
20 private:
21  struct ArgData {
22  const Expr *E = nullptr;
24  Optional<unsigned> Size;
26  Optional<const Expr *> Precision;
27  Optional<const Expr *> FieldWidth;
28  unsigned char Flags = 0;
29  };
30  SmallVector<ArgData, 4> ArgsData;
32 
35  switch (K) {
37  return OSLogBufferItem::StringKind;
39  return OSLogBufferItem::WideStringKind;
41  return OSLogBufferItem::PointerKind;
43  return OSLogBufferItem::ObjCObjKind;
45  return OSLogBufferItem::ErrnoKind;
46  default:
47  return OSLogBufferItem::ScalarKind;
48  }
49  }
50  }
51 
52 public:
53  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
54  ArgsData.reserve(Args.size());
55  }
56 
57  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
58  const char *StartSpecifier,
59  unsigned SpecifierLen) {
60  if (!FS.consumesDataArgument() &&
63  return true;
64 
65  ArgsData.emplace_back();
66  unsigned ArgIndex = FS.getArgIndex();
67  if (ArgIndex < Args.size())
68  ArgsData.back().E = Args[ArgIndex];
69 
70  // First get the Kind
71  ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
72  if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
73  !ArgsData.back().E) {
74  // missing argument
75  ArgsData.pop_back();
76  return false;
77  }
78 
79  switch (FS.getConversionSpecifier().getKind()) {
82  auto &precision = FS.getPrecision();
83  switch (precision.getHowSpecified()) {
85  break;
87  ArgsData.back().Size = precision.getConstantAmount();
88  break;
90  ArgsData.back().Count = Args[precision.getArgIndex()];
91  break;
93  return false;
94  }
95  break;
96  }
98  auto &precision = FS.getPrecision();
99  switch (precision.getHowSpecified()) {
101  return false; // length must be supplied with pointer format specifier
103  ArgsData.back().Size = precision.getConstantAmount();
104  break;
106  ArgsData.back().Count = Args[precision.getArgIndex()];
107  break;
109  return false;
110  }
111  break;
112  }
113  default:
114  if (FS.getPrecision().hasDataArgument()) {
115  ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
116  }
117  break;
118  }
119  if (FS.getFieldWidth().hasDataArgument()) {
120  ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
121  }
122 
123  if (FS.isPrivate()) {
124  ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
125  }
126  if (FS.isPublic()) {
127  ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
128  }
129  return true;
130  }
131 
132  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
133  Layout.Items.clear();
134  for (auto &Data : ArgsData) {
135  if (Data.FieldWidth) {
136  CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
137  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
138  Size, 0);
139  }
140  if (Data.Precision) {
141  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
142  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
143  Size, 0);
144  }
145  if (Data.Count) {
146  // "%.*P" has an extra "count" that we insert before the argument.
147  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
148  Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
149  0);
150  }
151  if (Data.Size)
152  Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
153  Data.Flags);
154  if (Data.Kind) {
155  CharUnits Size;
156  if (*Data.Kind == OSLogBufferItem::ErrnoKind)
157  Size = CharUnits::Zero();
158  else
159  Size = Ctx.getTypeSizeInChars(Data.E->getType());
160  Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
161  } else {
162  auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
163  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
164  Data.Flags);
165  }
166  }
167  }
168 };
169 } // end anonymous namespace
170 
172  ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
173  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
174 
175  const Expr *StringArg;
176  ArrayRef<const Expr *> VarArgs;
177  switch (E->getBuiltinCallee()) {
178  case Builtin::BI__builtin_os_log_format_buffer_size:
179  assert(E->getNumArgs() >= 1 &&
180  "__builtin_os_log_format_buffer_size takes at least 1 argument");
181  StringArg = E->getArg(0);
182  VarArgs = Args.slice(1);
183  break;
184  case Builtin::BI__builtin_os_log_format:
185  assert(E->getNumArgs() >= 2 &&
186  "__builtin_os_log_format takes at least 2 arguments");
187  StringArg = E->getArg(1);
188  VarArgs = Args.slice(2);
189  break;
190  default:
191  llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
192  }
193 
194  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
195  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
196  StringRef Data = Lit->getString();
197  OSLogFormatStringHandler H(VarArgs);
198  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
199  Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
200 
201  H.computeLayout(Ctx, Layout);
202  return true;
203 }
Expr ** getArgs()
Retrieve the call arguments.
Definition: Expr.h:2269
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2278
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2266
bool isAscii() const
Definition: Expr.h:1600
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:671
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
bool isUTF8() const
Definition: Expr.h:1602
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E, OSLogBufferLayout &layout)
Definition: OSLog.cpp:171
StringRef getString() const
Definition: Expr.h:1557
An OSLogBufferItem represents a single item in the data written by a call to os_log() or os_trace()...
Definition: OSLog.h:26
Expr - This represents one expression.
Definition: Expr.h:106
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
const OptionalAmount & getFieldWidth() const
Definition: FormatString.h:390
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
Definition: Expr.cpp:1279
Kind
const PrintfConversionSpecifier & getConversionSpecifier() const
Definition: FormatString.h:496
Dataflow Directional Tag Classes.
const OptionalFlag & isPrivate() const
Definition: FormatString.h:529
SmallVector< OSLogBufferItem, 4 > Items
Definition: OSLog.h:104
const OptionalAmount & getPrecision() const
Definition: FormatString.h:505
const OptionalFlag & isPublic() const
Definition: FormatString.h:530
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1509
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2209
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:915
bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target, bool isFreeBSDKPrintf)
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const LangOptions & getLangOpts() const
Definition: ASTContext.h:688
Defines enum values for all the target-independent builtin functions.