1 //= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines APIs for determining the layout of the data buffer for 11 // os_log() and os_trace(). 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H 16 #define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H 17 18 #include "clang/AST/ASTContext.h" 19 #include "clang/AST/Expr.h" 20 21 namespace clang { 22 namespace analyze_os_log { 23 24 /// An OSLogBufferItem represents a single item in the data written by a call 25 /// to os_log() or os_trace(). 26 class OSLogBufferItem { 27 public: 28 enum Kind { 29 // The item is a scalar (int, float, raw pointer, etc.). No further copying 30 // is required. This is the only kind allowed by os_trace(). 31 ScalarKind = 0, 32 33 // The item is a count, which describes the length of the following item to 34 // be copied. A count may only be followed by an item of kind StringKind, 35 // WideStringKind, or PointerKind. 36 CountKind, 37 38 // The item is a pointer to a C string. If preceded by a count 'n', 39 // os_log() will copy at most 'n' bytes from the pointer. 40 StringKind, 41 42 // The item is a pointer to a block of raw data. This item must be preceded 43 // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer. 44 PointerKind, 45 46 // The item is a pointer to an Objective-C object. os_log() may retain the 47 // object for later processing. 48 ObjCObjKind, 49 50 // The item is a pointer to wide-char string. 51 WideStringKind, 52 53 // The item is corresponding to the '%m' format specifier, no value is 54 // populated in the buffer and the runtime is loading the errno value. 55 ErrnoKind, 56 57 // The item is a mask type. 58 MaskKind 59 }; 60 61 enum { 62 // The item is marked "private" in the format string. 63 IsPrivate = 0x1, 64 65 // The item is marked "public" in the format string. 66 IsPublic = 0x2, 67 68 // The item is marked "sensitive" in the format string. 69 IsSensitive = 0x4 | IsPrivate 70 }; 71 72 private: 73 Kind TheKind = ScalarKind; 74 const Expr *TheExpr = nullptr; 75 CharUnits ConstValue; 76 CharUnits Size; // size of the data, not including the header bytes 77 unsigned Flags = 0; 78 StringRef MaskType; 79 80 public: 81 OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags, 82 StringRef maskType = StringRef()) TheKind(kind)83 : TheKind(kind), TheExpr(expr), Size(size), Flags(flags), 84 MaskType(maskType) { 85 assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) || 86 (Flags == IsSensitive)) && 87 "unexpected privacy flag"); 88 } 89 OSLogBufferItem(ASTContext & Ctx,CharUnits value,unsigned flags)90 OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags) 91 : TheKind(CountKind), ConstValue(value), 92 Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {} 93 getDescriptorByte()94 unsigned char getDescriptorByte() const { 95 unsigned char result = Flags; 96 result |= ((unsigned)getKind()) << 4; 97 return result; 98 } 99 getSizeByte()100 unsigned char getSizeByte() const { return size().getQuantity(); } 101 getKind()102 Kind getKind() const { return TheKind; } getIsPrivate()103 bool getIsPrivate() const { return (Flags & IsPrivate) != 0; } 104 getExpr()105 const Expr *getExpr() const { return TheExpr; } getConstValue()106 CharUnits getConstValue() const { return ConstValue; } size()107 CharUnits size() const { return Size; } 108 getMaskType()109 StringRef getMaskType() const { return MaskType; } 110 }; 111 112 class OSLogBufferLayout { 113 public: 114 SmallVector<OSLogBufferItem, 4> Items; 115 116 enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 }; 117 size()118 CharUnits size() const { 119 CharUnits result; 120 result += CharUnits::fromQuantity(2); // summary byte, num-args byte 121 for (auto &item : Items) { 122 // descriptor byte, size byte 123 result += item.size() + CharUnits::fromQuantity(2); 124 } 125 return result; 126 } 127 hasPrivateItems()128 bool hasPrivateItems() const { 129 return llvm::any_of( 130 Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); }); 131 } 132 hasNonScalarOrMask()133 bool hasNonScalarOrMask() const { 134 return llvm::any_of(Items, [](const OSLogBufferItem &Item) { 135 return Item.getKind() != OSLogBufferItem::ScalarKind || 136 !Item.getMaskType().empty(); 137 }); 138 } 139 getSummaryByte()140 unsigned char getSummaryByte() const { 141 unsigned char result = 0; 142 if (hasPrivateItems()) 143 result |= HasPrivateItems; 144 if (hasNonScalarOrMask()) 145 result |= HasNonScalarItems; 146 return result; 147 } 148 getNumArgsByte()149 unsigned char getNumArgsByte() const { return Items.size(); } 150 }; 151 152 // Given a call 'E' to one of the builtins __builtin_os_log_format() or 153 // __builtin_os_log_format_buffer_size(), compute the layout of the buffer that 154 // the call will write into and store it in 'layout'. Returns 'false' if there 155 // was some error encountered while computing the layout, and 'true' otherwise. 156 bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E, 157 OSLogBufferLayout &layout); 158 159 } // namespace analyze_os_log 160 } // namespace clang 161 #endif 162