clang  8.0.0svn
OSLog.cpp
Go to the documentation of this file.
1 // TODO: header template
2 
3 #include "clang/AST/OSLog.h"
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  StringRef MaskType;
30  };
31  SmallVector<ArgData, 4> ArgsData;
33 
36  switch (K) {
38  return OSLogBufferItem::StringKind;
40  return OSLogBufferItem::WideStringKind;
42  return OSLogBufferItem::PointerKind;
44  return OSLogBufferItem::ObjCObjKind;
46  return OSLogBufferItem::ErrnoKind;
47  default:
48  return OSLogBufferItem::ScalarKind;
49  }
50  }
51  }
52 
53 public:
54  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
55  ArgsData.reserve(Args.size());
56  }
57 
58  virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
59  const char *StartSpecifier,
60  unsigned SpecifierLen) {
61  if (!FS.consumesDataArgument() &&
64  return true;
65 
66  ArgsData.emplace_back();
67  unsigned ArgIndex = FS.getArgIndex();
68  if (ArgIndex < Args.size())
69  ArgsData.back().E = Args[ArgIndex];
70 
71  // First get the Kind
72  ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
73  if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
74  !ArgsData.back().E) {
75  // missing argument
76  ArgsData.pop_back();
77  return false;
78  }
79 
80  switch (FS.getConversionSpecifier().getKind()) {
83  auto &precision = FS.getPrecision();
84  switch (precision.getHowSpecified()) {
86  break;
88  ArgsData.back().Size = precision.getConstantAmount();
89  break;
91  ArgsData.back().Count = Args[precision.getArgIndex()];
92  break;
94  return false;
95  }
96  break;
97  }
99  auto &precision = FS.getPrecision();
100  switch (precision.getHowSpecified()) {
102  return false; // length must be supplied with pointer format specifier
104  ArgsData.back().Size = precision.getConstantAmount();
105  break;
107  ArgsData.back().Count = Args[precision.getArgIndex()];
108  break;
110  return false;
111  }
112  break;
113  }
114  default:
115  if (FS.getPrecision().hasDataArgument()) {
116  ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
117  }
118  break;
119  }
120  if (FS.getFieldWidth().hasDataArgument()) {
121  ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
122  }
123 
124  if (FS.isSensitive())
125  ArgsData.back().Flags |= OSLogBufferItem::IsSensitive;
126  else if (FS.isPrivate())
127  ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
128  else if (FS.isPublic())
129  ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
130 
131  ArgsData.back().MaskType = FS.getMaskType();
132  return true;
133  }
134 
135  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
136  Layout.Items.clear();
137  for (auto &Data : ArgsData) {
138  if (!Data.MaskType.empty()) {
140  Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr,
141  Size, 0, Data.MaskType);
142  }
143 
144  if (Data.FieldWidth) {
145  CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
146  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
147  Size, 0);
148  }
149  if (Data.Precision) {
150  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
151  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
152  Size, 0);
153  }
154  if (Data.Count) {
155  // "%.*P" has an extra "count" that we insert before the argument.
156  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
157  Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
158  0);
159  }
160  if (Data.Size)
161  Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
162  Data.Flags);
163  if (Data.Kind) {
164  CharUnits Size;
165  if (*Data.Kind == OSLogBufferItem::ErrnoKind)
166  Size = CharUnits::Zero();
167  else
168  Size = Ctx.getTypeSizeInChars(Data.E->getType());
169  Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
170  } else {
171  auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
172  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
173  Data.Flags);
174  }
175  }
176  }
177 };
178 } // end anonymous namespace
179 
181  ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
182  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
183 
184  const Expr *StringArg;
185  ArrayRef<const Expr *> VarArgs;
186  switch (E->getBuiltinCallee()) {
187  case Builtin::BI__builtin_os_log_format_buffer_size:
188  assert(E->getNumArgs() >= 1 &&
189  "__builtin_os_log_format_buffer_size takes at least 1 argument");
190  StringArg = E->getArg(0);
191  VarArgs = Args.slice(1);
192  break;
193  case Builtin::BI__builtin_os_log_format:
194  assert(E->getNumArgs() >= 2 &&
195  "__builtin_os_log_format takes at least 2 arguments");
196  StringArg = E->getArg(1);
197  VarArgs = Args.slice(2);
198  break;
199  default:
200  llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
201  }
202 
203  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
204  assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
205  StringRef Data = Lit->getString();
206  OSLogFormatStringHandler H(VarArgs);
207  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
208  Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
209 
210  H.computeLayout(Ctx, Layout);
211  return true;
212 }
Expr ** getArgs()
Retrieve the call arguments.
Definition: Expr.h:2486
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2495
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2483
bool isAscii() const
Definition: Expr.h:1696
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:689
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
bool isUTF8() const
Definition: Expr.h:1698
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:180
StringRef getString() const
Definition: Expr.h:1660
An OSLogBufferItem represents a single item in the data written by a call to os_log() or os_trace()...
Definition: OSLog.h:26
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:422
const OptionalFlag & isSensitive() const
Definition: FormatString.h:580
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
Definition: Expr.cpp:1320
Kind
const PrintfConversionSpecifier & getConversionSpecifier() const
Definition: FormatString.h:545
Dataflow Directional Tag Classes.
const OptionalFlag & isPrivate() const
Definition: FormatString.h:578
SmallVector< OSLogBufferItem, 4 > Items
Definition: OSLog.h:114
const OptionalAmount & getPrecision() const
Definition: FormatString.h:554
const OptionalFlag & isPublic() const
Definition: FormatString.h:579
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:1577
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2407
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:954
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:706
Defines enum values for all the target-independent builtin functions.