Retro68/gcc/libsanitizer/ubsan/ubsan_diag.h

267 lines
7.6 KiB
C
Raw Normal View History

2014-09-21 17:33:12 +00:00
//===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2014-09-21 17:33:12 +00:00
//
//===----------------------------------------------------------------------===//
//
// Diagnostics emission for Clang's undefined behavior sanitizer.
//
//===----------------------------------------------------------------------===//
#ifndef UBSAN_DIAG_H
#define UBSAN_DIAG_H
#include "ubsan_value.h"
2015-08-28 15:33:40 +00:00
#include "sanitizer_common/sanitizer_stacktrace.h"
2017-04-10 11:32:00 +00:00
#include "sanitizer_common/sanitizer_symbolizer.h"
2014-09-21 17:33:12 +00:00
namespace __ubsan {
2017-04-10 11:32:00 +00:00
class SymbolizedStackHolder {
SymbolizedStack *Stack;
void clear() {
if (Stack)
Stack->ClearAll();
}
2014-09-21 17:33:12 +00:00
public:
2017-04-10 11:32:00 +00:00
explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
: Stack(Stack) {}
~SymbolizedStackHolder() { clear(); }
void reset(SymbolizedStack *S) {
if (Stack != S)
clear();
Stack = S;
}
const SymbolizedStack *get() const { return Stack; }
2014-09-21 17:33:12 +00:00
};
2017-04-10 11:32:00 +00:00
SymbolizedStack *getSymbolizedLocation(uptr PC);
inline SymbolizedStack *getCallerLocation(uptr CallerPC) {
CHECK(CallerPC);
uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC);
return getSymbolizedLocation(PC);
}
2014-09-21 17:33:12 +00:00
/// A location of some data within the program's address space.
typedef uptr MemoryLocation;
/// \brief Location at which a diagnostic can be emitted. Either a
2017-04-10 11:32:00 +00:00
/// SourceLocation, a MemoryLocation, or a SymbolizedStack.
2014-09-21 17:33:12 +00:00
class Location {
public:
2017-04-10 11:32:00 +00:00
enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };
2014-09-21 17:33:12 +00:00
private:
LocationKind Kind;
// FIXME: In C++11, wrap these in an anonymous union.
SourceLocation SourceLoc;
MemoryLocation MemoryLoc;
2017-04-10 11:32:00 +00:00
const SymbolizedStack *SymbolizedLoc; // Not owned.
2014-09-21 17:33:12 +00:00
public:
Location() : Kind(LK_Null) {}
Location(SourceLocation Loc) :
Kind(LK_Source), SourceLoc(Loc) {}
Location(MemoryLocation Loc) :
Kind(LK_Memory), MemoryLoc(Loc) {}
2017-04-10 11:32:00 +00:00
// SymbolizedStackHolder must outlive Location object.
Location(const SymbolizedStackHolder &Stack) :
Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}
2014-09-21 17:33:12 +00:00
LocationKind getKind() const { return Kind; }
bool isSourceLocation() const { return Kind == LK_Source; }
bool isMemoryLocation() const { return Kind == LK_Memory; }
2017-04-10 11:32:00 +00:00
bool isSymbolizedStack() const { return Kind == LK_Symbolized; }
2014-09-21 17:33:12 +00:00
SourceLocation getSourceLocation() const {
CHECK(isSourceLocation());
return SourceLoc;
}
MemoryLocation getMemoryLocation() const {
CHECK(isMemoryLocation());
return MemoryLoc;
}
2017-04-10 11:32:00 +00:00
const SymbolizedStack *getSymbolizedStack() const {
CHECK(isSymbolizedStack());
return SymbolizedLoc;
}
2014-09-21 17:33:12 +00:00
};
/// A diagnostic severity level.
enum DiagLevel {
DL_Error, ///< An error.
DL_Note ///< A note, attached to a prior diagnostic.
};
/// \brief Annotation for a range of locations in a diagnostic.
class Range {
Location Start, End;
const char *Text;
public:
Range() : Start(), End(), Text() {}
Range(MemoryLocation Start, MemoryLocation End, const char *Text)
: Start(Start), End(End), Text(Text) {}
Location getStart() const { return Start; }
Location getEnd() const { return End; }
const char *getText() const { return Text; }
};
2017-04-10 11:32:00 +00:00
/// \brief A C++ type name. Really just a strong typedef for 'const char*'.
class TypeName {
2014-09-21 17:33:12 +00:00
const char *Name;
public:
2017-04-10 11:32:00 +00:00
TypeName(const char *Name) : Name(Name) {}
2014-09-21 17:33:12 +00:00
const char *getName() const { return Name; }
};
2019-06-02 15:48:37 +00:00
enum class ErrorType {
#define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
#include "ubsan_checks.inc"
#undef UBSAN_CHECK
};
2014-09-21 17:33:12 +00:00
/// \brief Representation of an in-flight diagnostic.
///
/// Temporary \c Diag instances are created by the handler routines to
/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
/// message.
class Diag {
/// The location at which the problem occurred.
Location Loc;
/// The diagnostic level.
DiagLevel Level;
2019-06-02 15:48:37 +00:00
/// The error type.
ErrorType ET;
2014-09-21 17:33:12 +00:00
/// The message which will be emitted, with %0, %1, ... placeholders for
/// arguments.
const char *Message;
public:
/// Kinds of arguments, corresponding to members of \c Arg's union.
enum ArgKind {
AK_String, ///< A string argument, displayed as-is.
2017-04-10 11:32:00 +00:00
AK_TypeName,///< A C++ type name, possibly demangled before display.
2014-09-21 17:33:12 +00:00
AK_UInt, ///< An unsigned integer argument.
AK_SInt, ///< A signed integer argument.
AK_Float, ///< A floating-point argument.
AK_Pointer ///< A pointer argument, displayed in hexadecimal.
};
/// An individual diagnostic message argument.
struct Arg {
Arg() {}
Arg(const char *String) : Kind(AK_String), String(String) {}
2017-04-10 11:32:00 +00:00
Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {}
2014-09-21 17:33:12 +00:00
Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
ArgKind Kind;
union {
const char *String;
UIntMax UInt;
SIntMax SInt;
FloatMax Float;
const void *Pointer;
};
};
private:
2019-06-02 15:48:37 +00:00
static const unsigned MaxArgs = 8;
2014-09-21 17:33:12 +00:00
static const unsigned MaxRanges = 1;
/// The arguments which have been added to this diagnostic so far.
Arg Args[MaxArgs];
unsigned NumArgs;
/// The ranges which have been added to this diagnostic so far.
Range Ranges[MaxRanges];
unsigned NumRanges;
Diag &AddArg(Arg A) {
CHECK(NumArgs != MaxArgs);
Args[NumArgs++] = A;
return *this;
}
Diag &AddRange(Range A) {
CHECK(NumRanges != MaxRanges);
Ranges[NumRanges++] = A;
return *this;
}
/// \c Diag objects are not copyable.
Diag(const Diag &); // NOT IMPLEMENTED
Diag &operator=(const Diag &);
public:
2019-06-02 15:48:37 +00:00
Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message)
: Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0),
NumRanges(0) {}
2014-09-21 17:33:12 +00:00
~Diag();
Diag &operator<<(const char *Str) { return AddArg(Str); }
2017-04-10 11:32:00 +00:00
Diag &operator<<(TypeName TN) { return AddArg(TN); }
2014-09-21 17:33:12 +00:00
Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
Diag &operator<<(const void *V) { return AddArg(V); }
Diag &operator<<(const TypeDescriptor &V);
Diag &operator<<(const Value &V);
Diag &operator<<(const Range &R) { return AddRange(R); }
};
2015-08-28 15:33:40 +00:00
struct ReportOptions {
// If FromUnrecoverableHandler is specified, UBSan runtime handler is not
// expected to return.
bool FromUnrecoverableHandler;
2015-08-28 15:33:40 +00:00
/// pc/bp are used to unwind the stack trace.
uptr pc;
uptr bp;
};
bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
#define GET_REPORT_OPTIONS(unrecoverable_handler) \
2015-08-28 15:33:40 +00:00
GET_CALLER_PC_BP; \
ReportOptions Opts = {unrecoverable_handler, pc, bp}
2015-08-28 15:33:40 +00:00
/// \brief Instantiate this class before printing diagnostics in the error
/// report. This class ensures that reports from different threads and from
/// different sanitizers won't be mixed.
class ScopedReport {
2018-12-28 15:30:48 +00:00
struct Initializer {
Initializer();
};
Initializer initializer_;
ScopedErrorReportLock report_lock_;
2015-08-28 15:33:40 +00:00
ReportOptions Opts;
Location SummaryLoc;
2017-04-10 11:32:00 +00:00
ErrorType Type;
2015-08-28 15:33:40 +00:00
public:
ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
2015-08-28 15:33:40 +00:00
~ScopedReport();
2018-12-28 15:30:48 +00:00
static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
2015-08-28 15:33:40 +00:00
};
2017-04-10 11:32:00 +00:00
void InitializeSuppressions();
bool IsVptrCheckSuppressed(const char *TypeName);
// Sometimes UBSan runtime can know filename from handlers arguments, even if
// debug info is missing.
bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
2015-08-28 15:33:40 +00:00
2014-09-21 17:33:12 +00:00
} // namespace __ubsan
#endif // UBSAN_DIAG_H