clang  19.0.0git
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 #include <optional>
12 
13 using namespace clang;
14 
17 
18 namespace {
19 class OSLogFormatStringHandler
21 private:
22  struct ArgData {
23  const Expr *E = nullptr;
24  std::optional<OSLogBufferItem::Kind> Kind;
25  std::optional<unsigned> Size;
26  std::optional<const Expr *> Count;
27  std::optional<const Expr *> Precision;
28  std::optional<const Expr *> FieldWidth;
29  unsigned char Flags = 0;
30  StringRef MaskType;
31  };
32  SmallVector<ArgData, 4> ArgsData;
34 
37  switch (K) {
39  return OSLogBufferItem::StringKind;
41  return OSLogBufferItem::WideStringKind;
43  return OSLogBufferItem::PointerKind;
45  return OSLogBufferItem::ObjCObjKind;
47  return OSLogBufferItem::ErrnoKind;
48  default:
49  return OSLogBufferItem::ScalarKind;
50  }
51  }
52  }
53 
54 public:
55  OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
56  ArgsData.reserve(Args.size());
57  }
58 
59  bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
60  const char *StartSpecifier, unsigned SpecifierLen,
61  const TargetInfo &) override {
62  if (!FS.consumesDataArgument() &&
63  FS.getConversionSpecifier().getKind() !=
65  return true;
66 
67  ArgsData.emplace_back();
68  unsigned ArgIndex = FS.getArgIndex();
69  if (ArgIndex < Args.size())
70  ArgsData.back().E = Args[ArgIndex];
71 
72  // First get the Kind
73  ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
74  if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
75  !ArgsData.back().E) {
76  // missing argument
77  ArgsData.pop_back();
78  return false;
79  }
80 
81  switch (FS.getConversionSpecifier().getKind()) {
84  auto &precision = FS.getPrecision();
85  switch (precision.getHowSpecified()) {
87  break;
89  ArgsData.back().Size = precision.getConstantAmount();
90  break;
92  ArgsData.back().Count = Args[precision.getArgIndex()];
93  break;
95  return false;
96  }
97  break;
98  }
100  auto &precision = FS.getPrecision();
101  switch (precision.getHowSpecified()) {
103  return false; // length must be supplied with pointer format specifier
105  ArgsData.back().Size = precision.getConstantAmount();
106  break;
108  ArgsData.back().Count = Args[precision.getArgIndex()];
109  break;
111  return false;
112  }
113  break;
114  }
115  default:
116  if (FS.getPrecision().hasDataArgument()) {
117  ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
118  }
119  break;
120  }
121  if (FS.getFieldWidth().hasDataArgument()) {
122  ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
123  }
124 
125  if (FS.isSensitive())
126  ArgsData.back().Flags |= OSLogBufferItem::IsSensitive;
127  else if (FS.isPrivate())
128  ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
129  else if (FS.isPublic())
130  ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
131 
132  ArgsData.back().MaskType = FS.getMaskType();
133  return true;
134  }
135 
136  void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
137  Layout.Items.clear();
138  for (auto &Data : ArgsData) {
139  if (!Data.MaskType.empty()) {
141  Layout.Items.emplace_back(OSLogBufferItem::MaskKind, nullptr,
142  Size, 0, Data.MaskType);
143  }
144 
145  if (Data.FieldWidth) {
146  CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
147  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
148  Size, 0);
149  }
150  if (Data.Precision) {
151  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
152  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
153  Size, 0);
154  }
155  if (Data.Count) {
156  // "%.*P" has an extra "count" that we insert before the argument.
157  CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
158  Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
159  0);
160  }
161  if (Data.Size)
162  Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
163  Data.Flags);
164  if (Data.Kind) {
165  CharUnits Size;
166  if (*Data.Kind == OSLogBufferItem::ErrnoKind)
167  Size = CharUnits::Zero();
168  else
169  Size = Ctx.getTypeSizeInChars(Data.E->getType());
170  Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
171  } else {
172  auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
173  Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
174  Data.Flags);
175  }
176  }
177  }
178 };
179 } // end anonymous namespace
180 
182  ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
183  ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
184 
185  const Expr *StringArg;
186  ArrayRef<const Expr *> VarArgs;
187  switch (E->getBuiltinCallee()) {
188  case Builtin::BI__builtin_os_log_format_buffer_size:
189  assert(E->getNumArgs() >= 1 &&
190  "__builtin_os_log_format_buffer_size takes at least 1 argument");
191  StringArg = E->getArg(0);
192  VarArgs = Args.slice(1);
193  break;
194  case Builtin::BI__builtin_os_log_format:
195  assert(E->getNumArgs() >= 2 &&
196  "__builtin_os_log_format takes at least 2 arguments");
197  StringArg = E->getArg(1);
198  VarArgs = Args.slice(2);
199  break;
200  default:
201  llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
202  }
203 
204  const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
205  assert(Lit && (Lit->isOrdinary() || Lit->isUTF8()));
206  StringRef Data = Lit->getString();
207  OSLogFormatStringHandler H(VarArgs);
208  ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
209  Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
210 
211  H.computeLayout(Ctx, Layout);
212  return true;
213 }
Defines enum values for all the target-independent builtin functions.
static Decl::Kind getKind(const Decl *D)
Definition: DeclBase.cpp:1125
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
const char * Data
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
const LangOptions & getLangOpts() const
Definition: ASTContext.h:778
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:760
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2872
Expr ** getArgs()
Retrieve the call arguments.
Definition: Expr.h:3053
unsigned getBuiltinCallee() const
getBuiltinCallee - If this is a call to a builtin, return the builtin ID of the callee.
Definition: Expr.cpp:1634
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:3050
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:3063
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
This represents one expression.
Definition: Expr.h:110
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:3116
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1773
bool isUTF8() const
Definition: Expr.h:1899
StringRef getString() const
Definition: Expr.h:1850
bool isOrdinary() const
Definition: Expr.h:1897
Exposes information about the current target.
Definition: TargetInfo.h:218
An OSLogBufferItem represents a single item in the data written by a call to os_log() or os_trace().
Definition: OSLog.h:25
SmallVector< OSLogBufferItem, 4 > Items
Definition: OSLog.h:113
bool ParsePrintfString(FormatStringHandler &H, const char *beg, const char *end, const LangOptions &LO, const TargetInfo &Target, bool isFreeBSDKPrintf)
bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E, OSLogBufferLayout &layout)
Definition: OSLog.cpp:181
The JSON file list parser is used to communicate input to InstallAPI.