xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_value.h (revision e25152834cdf3b353892835a4f3b157e066a8ed4)
10b57cec5SDimitry Andric //===-- ubsan_value.h -------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Representation of data which is passed from the compiler-generated calls into
100b57cec5SDimitry Andric // the ubsan runtime.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric #ifndef UBSAN_VALUE_H
140b57cec5SDimitry Andric #define UBSAN_VALUE_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
170b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric // FIXME: Move this out to a config header.
200b57cec5SDimitry Andric #if __SIZEOF_INT128__
210b57cec5SDimitry Andric __extension__ typedef __int128 s128;
220b57cec5SDimitry Andric __extension__ typedef unsigned __int128 u128;
230b57cec5SDimitry Andric #define HAVE_INT128_T 1
240b57cec5SDimitry Andric #else
250b57cec5SDimitry Andric #define HAVE_INT128_T 0
260b57cec5SDimitry Andric #endif
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace __ubsan {
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric /// \brief Largest integer types we support.
310b57cec5SDimitry Andric #if HAVE_INT128_T
320b57cec5SDimitry Andric typedef s128 SIntMax;
330b57cec5SDimitry Andric typedef u128 UIntMax;
340b57cec5SDimitry Andric #else
350b57cec5SDimitry Andric typedef s64 SIntMax;
360b57cec5SDimitry Andric typedef u64 UIntMax;
370b57cec5SDimitry Andric #endif
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric /// \brief Largest floating-point type we support.
400b57cec5SDimitry Andric typedef long double FloatMax;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric /// \brief A description of a source location. This corresponds to Clang's
430b57cec5SDimitry Andric /// \c PresumedLoc type.
440b57cec5SDimitry Andric class SourceLocation {
450b57cec5SDimitry Andric   const char *Filename;
460b57cec5SDimitry Andric   u32 Line;
470b57cec5SDimitry Andric   u32 Column;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric public:
SourceLocation()500b57cec5SDimitry Andric   SourceLocation() : Filename(), Line(), Column() {}
SourceLocation(const char * Filename,unsigned Line,unsigned Column)510b57cec5SDimitry Andric   SourceLocation(const char *Filename, unsigned Line, unsigned Column)
520b57cec5SDimitry Andric     : Filename(Filename), Line(Line), Column(Column) {}
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   /// \brief Determine whether the source location is known.
isInvalid()550b57cec5SDimitry Andric   bool isInvalid() const { return !Filename; }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   /// \brief Atomically acquire a copy, disabling original in-place.
580b57cec5SDimitry Andric   /// Exactly one call to acquire() returns a copy that isn't disabled.
acquire()590b57cec5SDimitry Andric   SourceLocation acquire() {
600b57cec5SDimitry Andric     u32 OldColumn = __sanitizer::atomic_exchange(
610b57cec5SDimitry Andric                         (__sanitizer::atomic_uint32_t *)&Column, ~u32(0),
620b57cec5SDimitry Andric                         __sanitizer::memory_order_relaxed);
630b57cec5SDimitry Andric     return SourceLocation(Filename, Line, OldColumn);
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   /// \brief Determine if this Location has been disabled.
670b57cec5SDimitry Andric   /// Disabled SourceLocations are invalid to use.
isDisabled()680b57cec5SDimitry Andric   bool isDisabled() {
690b57cec5SDimitry Andric     return Column == ~u32(0);
700b57cec5SDimitry Andric   }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric   /// \brief Get the presumed filename for the source location.
getFilename()730b57cec5SDimitry Andric   const char *getFilename() const { return Filename; }
740b57cec5SDimitry Andric   /// \brief Get the presumed line number.
getLine()750b57cec5SDimitry Andric   unsigned getLine() const { return Line; }
760b57cec5SDimitry Andric   /// \brief Get the column within the presumed line.
getColumn()770b57cec5SDimitry Andric   unsigned getColumn() const { return Column; }
780b57cec5SDimitry Andric };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric /// \brief A description of a type.
820b57cec5SDimitry Andric class TypeDescriptor {
830b57cec5SDimitry Andric   /// A value from the \c Kind enumeration, specifying what flavor of type we
840b57cec5SDimitry Andric   /// have.
850b57cec5SDimitry Andric   u16 TypeKind;
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   /// A \c Type-specific value providing information which allows us to
880b57cec5SDimitry Andric   /// interpret the meaning of a ValueHandle of this type.
890b57cec5SDimitry Andric   u16 TypeInfo;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   /// The name of the type follows, in a format suitable for including in
920b57cec5SDimitry Andric   /// diagnostics.
930b57cec5SDimitry Andric   char TypeName[1];
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric public:
960b57cec5SDimitry Andric   enum Kind {
970b57cec5SDimitry Andric     /// An integer type. Lowest bit is 1 for a signed value, 0 for an unsigned
980b57cec5SDimitry Andric     /// value. Remaining bits are log_2(bit width). The value representation is
990b57cec5SDimitry Andric     /// the integer itself if it fits into a ValueHandle, and a pointer to the
1000b57cec5SDimitry Andric     /// integer otherwise.
1010b57cec5SDimitry Andric     TK_Integer = 0x0000,
1020b57cec5SDimitry Andric     /// A floating-point type. Low 16 bits are bit width. The value
1030b57cec5SDimitry Andric     /// representation is that of bitcasting the floating-point value to an
1040b57cec5SDimitry Andric     /// integer type.
1050b57cec5SDimitry Andric     TK_Float = 0x0001,
1060b57cec5SDimitry Andric     /// Any other type. The value representation is unspecified.
1070b57cec5SDimitry Andric     TK_Unknown = 0xffff
1080b57cec5SDimitry Andric   };
1090b57cec5SDimitry Andric 
getTypeName()1100b57cec5SDimitry Andric   const char *getTypeName() const { return TypeName; }
1110b57cec5SDimitry Andric 
getKind()1120b57cec5SDimitry Andric   Kind getKind() const {
1130b57cec5SDimitry Andric     return static_cast<Kind>(TypeKind);
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric 
isIntegerTy()1160b57cec5SDimitry Andric   bool isIntegerTy() const { return getKind() == TK_Integer; }
isSignedIntegerTy()1170b57cec5SDimitry Andric   bool isSignedIntegerTy() const {
1180b57cec5SDimitry Andric     return isIntegerTy() && (TypeInfo & 1);
1190b57cec5SDimitry Andric   }
isUnsignedIntegerTy()1200b57cec5SDimitry Andric   bool isUnsignedIntegerTy() const {
1210b57cec5SDimitry Andric     return isIntegerTy() && !(TypeInfo & 1);
1220b57cec5SDimitry Andric   }
getIntegerBitWidth()1230b57cec5SDimitry Andric   unsigned getIntegerBitWidth() const {
1240b57cec5SDimitry Andric     CHECK(isIntegerTy());
1250b57cec5SDimitry Andric     return 1 << (TypeInfo >> 1);
1260b57cec5SDimitry Andric   }
1270b57cec5SDimitry Andric 
isFloatTy()1280b57cec5SDimitry Andric   bool isFloatTy() const { return getKind() == TK_Float; }
getFloatBitWidth()1290b57cec5SDimitry Andric   unsigned getFloatBitWidth() const {
1300b57cec5SDimitry Andric     CHECK(isFloatTy());
1310b57cec5SDimitry Andric     return TypeInfo;
1320b57cec5SDimitry Andric   }
1330b57cec5SDimitry Andric };
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric /// \brief An opaque handle to a value.
1360b57cec5SDimitry Andric typedef uptr ValueHandle;
1370b57cec5SDimitry Andric 
138*5ffd83dbSDimitry Andric /// Returns the class name of the given ObjC object, or null if the name
139*5ffd83dbSDimitry Andric /// cannot be found.
140*5ffd83dbSDimitry Andric const char *getObjCClassName(ValueHandle Pointer);
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric /// \brief Representation of an operand value provided by the instrumented code.
1430b57cec5SDimitry Andric ///
1440b57cec5SDimitry Andric /// This is a combination of a TypeDescriptor (which is emitted as constant data
1450b57cec5SDimitry Andric /// as an operand to a handler function) and a ValueHandle (which is passed at
1460b57cec5SDimitry Andric /// runtime when a check failure occurs).
1470b57cec5SDimitry Andric class Value {
1480b57cec5SDimitry Andric   /// The type of the value.
1490b57cec5SDimitry Andric   const TypeDescriptor &Type;
1500b57cec5SDimitry Andric   /// The encoded value itself.
1510b57cec5SDimitry Andric   ValueHandle Val;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   /// Is \c Val a (zero-extended) integer?
isInlineInt()1540b57cec5SDimitry Andric   bool isInlineInt() const {
1550b57cec5SDimitry Andric     CHECK(getType().isIntegerTy());
1560b57cec5SDimitry Andric     const unsigned InlineBits = sizeof(ValueHandle) * 8;
1570b57cec5SDimitry Andric     const unsigned Bits = getType().getIntegerBitWidth();
1580b57cec5SDimitry Andric     return Bits <= InlineBits;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   /// Is \c Val a (zero-extended) integer representation of a float?
isInlineFloat()1620b57cec5SDimitry Andric   bool isInlineFloat() const {
1630b57cec5SDimitry Andric     CHECK(getType().isFloatTy());
1640b57cec5SDimitry Andric     const unsigned InlineBits = sizeof(ValueHandle) * 8;
1650b57cec5SDimitry Andric     const unsigned Bits = getType().getFloatBitWidth();
1660b57cec5SDimitry Andric     return Bits <= InlineBits;
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric public:
Value(const TypeDescriptor & Type,ValueHandle Val)1700b57cec5SDimitry Andric   Value(const TypeDescriptor &Type, ValueHandle Val) : Type(Type), Val(Val) {}
1710b57cec5SDimitry Andric 
getType()1720b57cec5SDimitry Andric   const TypeDescriptor &getType() const { return Type; }
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric   /// \brief Get this value as a signed integer.
1750b57cec5SDimitry Andric   SIntMax getSIntValue() const;
1760b57cec5SDimitry Andric 
1770b57cec5SDimitry Andric   /// \brief Get this value as an unsigned integer.
1780b57cec5SDimitry Andric   UIntMax getUIntValue() const;
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric   /// \brief Decode this value, which must be a positive or unsigned integer.
1810b57cec5SDimitry Andric   UIntMax getPositiveIntValue() const;
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   /// Is this an integer with value -1?
isMinusOne()1840b57cec5SDimitry Andric   bool isMinusOne() const {
1850b57cec5SDimitry Andric     return getType().isSignedIntegerTy() && getSIntValue() == -1;
1860b57cec5SDimitry Andric   }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   /// Is this a negative integer?
isNegative()1890b57cec5SDimitry Andric   bool isNegative() const {
1900b57cec5SDimitry Andric     return getType().isSignedIntegerTy() && getSIntValue() < 0;
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   /// \brief Get this value as a floating-point quantity.
1940b57cec5SDimitry Andric   FloatMax getFloatValue() const;
1950b57cec5SDimitry Andric };
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric } // namespace __ubsan
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric #endif // UBSAN_VALUE_H
200