1//===-- ubsan_diag.h --------------------------------------------*- 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// Diagnostics emission for Clang's undefined behavior sanitizer.
11//
12//===----------------------------------------------------------------------===//
13#ifndef UBSAN_DIAG_H
14#define UBSAN_DIAG_H
15
16#include "ubsan_value.h"
17
18namespace __ubsan {
19
20/// \brief A location within a loaded module in the program. These are used when
21/// the location can't be resolved to a SourceLocation.
22class ModuleLocation {
23  const char *ModuleName;
24  uptr Offset;
25
26public:
27  ModuleLocation() : ModuleName(0), Offset(0) {}
28  ModuleLocation(const char *ModuleName, uptr Offset)
29    : ModuleName(ModuleName), Offset(Offset) {}
30  const char *getModuleName() const { return ModuleName; }
31  uptr getOffset() const { return Offset; }
32};
33
34/// A location of some data within the program's address space.
35typedef uptr MemoryLocation;
36
37/// \brief Location at which a diagnostic can be emitted. Either a
38/// SourceLocation, a ModuleLocation, or a MemoryLocation.
39class Location {
40public:
41  enum LocationKind { LK_Null, LK_Source, LK_Module, LK_Memory };
42
43private:
44  LocationKind Kind;
45  // FIXME: In C++11, wrap these in an anonymous union.
46  SourceLocation SourceLoc;
47  ModuleLocation ModuleLoc;
48  MemoryLocation MemoryLoc;
49
50public:
51  Location() : Kind(LK_Null) {}
52  Location(SourceLocation Loc) :
53    Kind(LK_Source), SourceLoc(Loc) {}
54  Location(ModuleLocation Loc) :
55    Kind(LK_Module), ModuleLoc(Loc) {}
56  Location(MemoryLocation Loc) :
57    Kind(LK_Memory), MemoryLoc(Loc) {}
58
59  LocationKind getKind() const { return Kind; }
60
61  bool isSourceLocation() const { return Kind == LK_Source; }
62  bool isModuleLocation() const { return Kind == LK_Module; }
63  bool isMemoryLocation() const { return Kind == LK_Memory; }
64
65  SourceLocation getSourceLocation() const {
66    CHECK(isSourceLocation());
67    return SourceLoc;
68  }
69  ModuleLocation getModuleLocation() const {
70    CHECK(isModuleLocation());
71    return ModuleLoc;
72  }
73  MemoryLocation getMemoryLocation() const {
74    CHECK(isMemoryLocation());
75    return MemoryLoc;
76  }
77};
78
79/// Try to obtain a location for the caller. This might fail, and produce either
80/// an invalid location or a module location for the caller.
81Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
82
83/// Try to obtain a location for the given function pointer. This might fail,
84/// and produce either an invalid location or a module location for the caller.
85/// If FName is non-null and the name of the function is known, set *FName to
86/// the function name, otherwise *FName is unchanged.
87Location getFunctionLocation(uptr Loc, const char **FName);
88
89/// A diagnostic severity level.
90enum DiagLevel {
91  DL_Error, ///< An error.
92  DL_Note   ///< A note, attached to a prior diagnostic.
93};
94
95/// \brief Annotation for a range of locations in a diagnostic.
96class Range {
97  Location Start, End;
98  const char *Text;
99
100public:
101  Range() : Start(), End(), Text() {}
102  Range(MemoryLocation Start, MemoryLocation End, const char *Text)
103    : Start(Start), End(End), Text(Text) {}
104  Location getStart() const { return Start; }
105  Location getEnd() const { return End; }
106  const char *getText() const { return Text; }
107};
108
109/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'.
110class MangledName {
111  const char *Name;
112public:
113  MangledName(const char *Name) : Name(Name) {}
114  const char *getName() const { return Name; }
115};
116
117/// \brief Representation of an in-flight diagnostic.
118///
119/// Temporary \c Diag instances are created by the handler routines to
120/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
121/// message.
122class Diag {
123  /// The location at which the problem occurred.
124  Location Loc;
125
126  /// The diagnostic level.
127  DiagLevel Level;
128
129  /// The message which will be emitted, with %0, %1, ... placeholders for
130  /// arguments.
131  const char *Message;
132
133public:
134  /// Kinds of arguments, corresponding to members of \c Arg's union.
135  enum ArgKind {
136    AK_String, ///< A string argument, displayed as-is.
137    AK_Mangled,///< A C++ mangled name, demangled before display.
138    AK_UInt,   ///< An unsigned integer argument.
139    AK_SInt,   ///< A signed integer argument.
140    AK_Float,  ///< A floating-point argument.
141    AK_Pointer ///< A pointer argument, displayed in hexadecimal.
142  };
143
144  /// An individual diagnostic message argument.
145  struct Arg {
146    Arg() {}
147    Arg(const char *String) : Kind(AK_String), String(String) {}
148    Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {}
149    Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
150    Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
151    Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
152    Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
153
154    ArgKind Kind;
155    union {
156      const char *String;
157      UIntMax UInt;
158      SIntMax SInt;
159      FloatMax Float;
160      const void *Pointer;
161    };
162  };
163
164private:
165  static const unsigned MaxArgs = 5;
166  static const unsigned MaxRanges = 1;
167
168  /// The arguments which have been added to this diagnostic so far.
169  Arg Args[MaxArgs];
170  unsigned NumArgs;
171
172  /// The ranges which have been added to this diagnostic so far.
173  Range Ranges[MaxRanges];
174  unsigned NumRanges;
175
176  Diag &AddArg(Arg A) {
177    CHECK(NumArgs != MaxArgs);
178    Args[NumArgs++] = A;
179    return *this;
180  }
181
182  Diag &AddRange(Range A) {
183    CHECK(NumRanges != MaxRanges);
184    Ranges[NumRanges++] = A;
185    return *this;
186  }
187
188  /// \c Diag objects are not copyable.
189  Diag(const Diag &); // NOT IMPLEMENTED
190  Diag &operator=(const Diag &);
191
192public:
193  Diag(Location Loc, DiagLevel Level, const char *Message)
194    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
195  ~Diag();
196
197  Diag &operator<<(const char *Str) { return AddArg(Str); }
198  Diag &operator<<(MangledName MN) { return AddArg(MN); }
199  Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
200  Diag &operator<<(const void *V) { return AddArg(V); }
201  Diag &operator<<(const TypeDescriptor &V);
202  Diag &operator<<(const Value &V);
203  Diag &operator<<(const Range &R) { return AddRange(R); }
204};
205
206} // namespace __ubsan
207
208#endif // UBSAN_DIAG_H
209