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