138032Speter//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============// 2261363Sgshapiro// 364562Sgshapiro// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 438032Speter// See https://llvm.org/LICENSE.txt for license information. 538032Speter// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 638032Speter// 738032Speter//===----------------------------------------------------------------------===// 838032Speter// 938032Speter// This file defines APIs for determining the layout of the data buffer for 1038032Speter// os_log() and os_trace(). 1138032Speter// 1238032Speter//===----------------------------------------------------------------------===// 1338032Speter 1464562Sgshapiro#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H 1538032Speter#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H 16266692Sgshapiro 1764562Sgshapiro#include "clang/AST/ASTContext.h" 1890792Sgshapiro#include "clang/AST/Expr.h" 1990792Sgshapiro 2090792Sgshapironamespace clang { 2190792Sgshapironamespace analyze_os_log { 2290792Sgshapiro 2338032Speter/// An OSLogBufferItem represents a single item in the data written by a call 2438032Speter/// to os_log() or os_trace(). 2538032Speterclass OSLogBufferItem { 2638032Speterpublic: 2738032Speter enum Kind { 2838032Speter // The item is a scalar (int, float, raw pointer, etc.). No further copying 2964562Sgshapiro // is required. This is the only kind allowed by os_trace(). 3064562Sgshapiro ScalarKind = 0, 3190792Sgshapiro 32110560Sgshapiro // The item is a count, which describes the length of the following item to 3364562Sgshapiro // be copied. A count may only be followed by an item of kind StringKind, 3490792Sgshapiro // WideStringKind, or PointerKind. 3538032Speter CountKind, 3638032Speter 3790792Sgshapiro // The item is a pointer to a C string. If preceded by a count 'n', 3838032Speter // os_log() will copy at most 'n' bytes from the pointer. 3964562Sgshapiro StringKind, 4064562Sgshapiro 4138032Speter // The item is a pointer to a block of raw data. This item must be preceded 42168515Sgshapiro // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer. 43168515Sgshapiro PointerKind, 4490792Sgshapiro 4564562Sgshapiro // The item is a pointer to an Objective-C object. os_log() may retain the 4664562Sgshapiro // object for later processing. 4764562Sgshapiro ObjCObjKind, 4864562Sgshapiro 4964562Sgshapiro // The item is a pointer to wide-char string. 5064562Sgshapiro WideStringKind, 5164562Sgshapiro 5264562Sgshapiro // The item is corresponding to the '%m' format specifier, no value is 5364562Sgshapiro // populated in the buffer and the runtime is loading the errno value. 5464562Sgshapiro ErrnoKind, 5573188Sgshapiro 5690792Sgshapiro // The item is a mask type. 5790792Sgshapiro MaskKind 5864562Sgshapiro }; 5990792Sgshapiro 6064562Sgshapiro enum { 6190792Sgshapiro // The item is marked "private" in the format string. 6264562Sgshapiro IsPrivate = 0x1, 6364562Sgshapiro 6490792Sgshapiro // The item is marked "public" in the format string. 6564562Sgshapiro IsPublic = 0x2, 6664562Sgshapiro 6764562Sgshapiro // The item is marked "sensitive" in the format string. 6864562Sgshapiro IsSensitive = 0x4 | IsPrivate 6964562Sgshapiro }; 7064562Sgshapiro 71132943Sgshapiroprivate: 72132943Sgshapiro Kind TheKind = ScalarKind; 7364562Sgshapiro const Expr *TheExpr = nullptr; 74132943Sgshapiro CharUnits ConstValue; 75132943Sgshapiro CharUnits Size; // size of the data, not including the header bytes 76132943Sgshapiro unsigned Flags = 0; 77132943Sgshapiro StringRef MaskType; 7890792Sgshapiro 7990792Sgshapiropublic: 8090792Sgshapiro OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags, 8190792Sgshapiro StringRef maskType = StringRef()) 8290792Sgshapiro : TheKind(kind), TheExpr(expr), Size(size), Flags(flags), 8390792Sgshapiro MaskType(maskType) { 8490792Sgshapiro assert(((Flags == 0) || (Flags == IsPrivate) || (Flags == IsPublic) || 8590792Sgshapiro (Flags == IsSensitive)) && 8690792Sgshapiro "unexpected privacy flag"); 8790792Sgshapiro } 8890792Sgshapiro 8938032Speter OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags) 9038032Speter : TheKind(CountKind), ConstValue(value), 9138032Speter Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {} 9238032Speter 9338032Speter unsigned char getDescriptorByte() const { 9438032Speter unsigned char result = Flags; 9590792Sgshapiro result |= ((unsigned)getKind()) << 4; 9690792Sgshapiro return result; 9738032Speter } 9838032Speter 9938032Speter unsigned char getSizeByte() const { return size().getQuantity(); } 10038032Speter 10138032Speter Kind getKind() const { return TheKind; } 10238032Speter bool getIsPrivate() const { return (Flags & IsPrivate) != 0; } 10338032Speter 10438032Speter const Expr *getExpr() const { return TheExpr; } 10538032Speter CharUnits getConstValue() const { return ConstValue; } 10638032Speter CharUnits size() const { return Size; } 10738032Speter 10838032Speter StringRef getMaskType() const { return MaskType; } 10938032Speter}; 11038032Speter 11138032Speterclass OSLogBufferLayout { 11238032Speterpublic: 11338032Speter SmallVector<OSLogBufferItem, 4> Items; 11490792Sgshapiro 11590792Sgshapiro enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 }; 11690792Sgshapiro 11738032Speter CharUnits size() const { 11838032Speter CharUnits result; 11938032Speter result += CharUnits::fromQuantity(2); // summary byte, num-args byte 12038032Speter for (auto &item : Items) { 12138032Speter // descriptor byte, size byte 12238032Speter result += item.size() + CharUnits::fromQuantity(2); 12338032Speter } 12438032Speter return result; 12538032Speter } 12638032Speter 12738032Speter bool hasPrivateItems() const { 12838032Speter return llvm::any_of( 12938032Speter Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); }); 13038032Speter } 13164562Sgshapiro 13238032Speter bool hasNonScalarOrMask() const { 13364562Sgshapiro return llvm::any_of(Items, [](const OSLogBufferItem &Item) { 13438032Speter return Item.getKind() != OSLogBufferItem::ScalarKind || 13590792Sgshapiro !Item.getMaskType().empty(); 13638032Speter }); 13738032Speter } 13838032Speter 13938032Speter unsigned char getSummaryByte() const { 14038032Speter unsigned char result = 0; 14138032Speter if (hasPrivateItems()) 14238032Speter result |= HasPrivateItems; 14338032Speter if (hasNonScalarOrMask()) 14438032Speter result |= HasNonScalarItems; 14590792Sgshapiro return result; 14690792Sgshapiro } 14738032Speter 14838032Speter unsigned char getNumArgsByte() const { return Items.size(); } 14938032Speter}; 15038032Speter 15138032Speter// Given a call 'E' to one of the builtins __builtin_os_log_format() or 15238032Speter// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that 15338032Speter// the call will write into and store it in 'layout'. Returns 'false' if there 15438032Speter// was some error encountered while computing the layout, and 'true' otherwise. 15538032Speterbool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E, 15638032Speter OSLogBufferLayout &layout); 15738032Speter 15838032Speter} // namespace analyze_os_log 15964562Sgshapiro} // namespace clang 16090792Sgshapiro#endif 16190792Sgshapiro