aboutsummaryrefslogtreecommitdiff
path: root/include/clang/AST/OSLog.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/AST/OSLog.h')
-rw-r--r--include/clang/AST/OSLog.h161
1 files changed, 161 insertions, 0 deletions
diff --git a/include/clang/AST/OSLog.h b/include/clang/AST/OSLog.h
new file mode 100644
index 000000000000..2b21855e7a6e
--- /dev/null
+++ b/include/clang/AST/OSLog.h
@@ -0,0 +1,161 @@
+//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines APIs for determining the layout of the data buffer for
+// os_log() and os_trace().
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Expr.h"
+
+namespace clang {
+namespace analyze_os_log {
+
+/// An OSLogBufferItem represents a single item in the data written by a call
+/// to os_log() or os_trace().
+class OSLogBufferItem {
+public:
+ enum Kind {
+ // The item is a scalar (int, float, raw pointer, etc.). No further copying
+ // is required. This is the only kind allowed by os_trace().
+ ScalarKind = 0,
+
+ // The item is a count, which describes the length of the following item to
+ // be copied. A count may only be followed by an item of kind StringKind,
+ // WideStringKind, or PointerKind.
+ CountKind,
+
+ // The item is a pointer to a C string. If preceded by a count 'n',
+ // os_log() will copy at most 'n' bytes from the pointer.
+ StringKind,
+
+ // The item is a pointer to a block of raw data. This item must be preceded
+ // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.
+ PointerKind,
+
+ // The item is a pointer to an Objective-C object. os_log() may retain the
+ // object for later processing.
+ ObjCObjKind,
+
+ // The item is a pointer to wide-char string.
+ WideStringKind,
+
+ // The item is corresponding to the '%m' format specifier, no value is
+ // populated in the buffer and the runtime is loading the errno value.
+ ErrnoKind,
+
+ // The item is a mask type.
+ MaskKind
+ };
+
+ enum {
+ // The item is marked "private" in the format string.
+ IsPrivate = 0x1,
+
+ // The item is marked "public" in the format string.
+ IsPublic = 0x2,
+
+ // The item is marked "sensitive" in the format string.
+ IsSensitive = 0x4 | IsPrivate
+ };
+
+private:
+ Kind TheKind = ScalarKind;
+ const Expr *TheExpr = nullptr;
+ CharUnits ConstValue;
+ CharUnits Size; // size of the data, not including the header bytes
+ unsigned Flags = 0;
+ StringRef MaskType;
+
+public:
+ OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags,
+ StringRef maskType = StringRef())
+ : TheKind(kind), TheExpr(expr), Size(size), Flags(flags),
+ MaskType(maskType) {
+ assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) ||
+ (Flags == IsSensitive)) &&
+ "unexpected privacy flag");
+ }
+
+ OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)
+ : TheKind(CountKind), ConstValue(value),
+ Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}
+
+ unsigned char getDescriptorByte() const {
+ unsigned char result = Flags;
+ result |= ((unsigned)getKind()) << 4;
+ return result;
+ }
+
+ unsigned char getSizeByte() const { return size().getQuantity(); }
+
+ Kind getKind() const { return TheKind; }
+ bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }
+
+ const Expr *getExpr() const { return TheExpr; }
+ CharUnits getConstValue() const { return ConstValue; }
+ CharUnits size() const { return Size; }
+
+ StringRef getMaskType() const { return MaskType; }
+};
+
+class OSLogBufferLayout {
+public:
+ SmallVector<OSLogBufferItem, 4> Items;
+
+ enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };
+
+ CharUnits size() const {
+ CharUnits result;
+ result += CharUnits::fromQuantity(2); // summary byte, num-args byte
+ for (auto &item : Items) {
+ // descriptor byte, size byte
+ result += item.size() + CharUnits::fromQuantity(2);
+ }
+ return result;
+ }
+
+ bool hasPrivateItems() const {
+ return llvm::any_of(
+ Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });
+ }
+
+ bool hasNonScalarOrMask() const {
+ return llvm::any_of(Items, [](const OSLogBufferItem &Item) {
+ return Item.getKind() != OSLogBufferItem::ScalarKind ||
+ !Item.getMaskType().empty();
+ });
+ }
+
+ unsigned char getSummaryByte() const {
+ unsigned char result = 0;
+ if (hasPrivateItems())
+ result |= HasPrivateItems;
+ if (hasNonScalarOrMask())
+ result |= HasNonScalarItems;
+ return result;
+ }
+
+ unsigned char getNumArgsByte() const { return Items.size(); }
+};
+
+// Given a call 'E' to one of the builtins __builtin_os_log_format() or
+// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that
+// the call will write into and store it in 'layout'. Returns 'false' if there
+// was some error encountered while computing the layout, and 'true' otherwise.
+bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,
+ OSLogBufferLayout &layout);
+
+} // namespace analyze_os_log
+} // namespace clang
+#endif