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/// A diagnostic severity level.
84enum DiagLevel {
85  DL_Error, ///< An error.
86  DL_Note   ///< A note, attached to a prior diagnostic.
87};
88
89/// \brief Annotation for a range of locations in a diagnostic.
90class Range {
91  Location Start, End;
92  const char *Text;
93
94public:
95  Range() : Start(), End(), Text() {}
96  Range(MemoryLocation Start, MemoryLocation End, const char *Text)
97    : Start(Start), End(End), Text(Text) {}
98  Location getStart() const { return Start; }
99  Location getEnd() const { return End; }
100  const char *getText() const { return Text; }
101};
102
103/// \brief A mangled C++ name. Really just a strong typedef for 'const char*'.
104class MangledName {
105  const char *Name;
106public:
107  MangledName(const char *Name) : Name(Name) {}
108  const char *getName() const { return Name; }
109};
110
111/// \brief Representation of an in-flight diagnostic.
112///
113/// Temporary \c Diag instances are created by the handler routines to
114/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
115/// message.
116class Diag {
117  /// The location at which the problem occurred.
118  Location Loc;
119
120  /// The diagnostic level.
121  DiagLevel Level;
122
123  /// The message which will be emitted, with %0, %1, ... placeholders for
124  /// arguments.
125  const char *Message;
126
127public:
128  /// Kinds of arguments, corresponding to members of \c Arg's union.
129  enum ArgKind {
130    AK_String, ///< A string argument, displayed as-is.
131    AK_Mangled,///< A C++ mangled name, demangled before display.
132    AK_UInt,   ///< An unsigned integer argument.
133    AK_SInt,   ///< A signed integer argument.
134    AK_Float,  ///< A floating-point argument.
135    AK_Pointer ///< A pointer argument, displayed in hexadecimal.
136  };
137
138  /// An individual diagnostic message argument.
139  struct Arg {
140    Arg() {}
141    Arg(const char *String) : Kind(AK_String), String(String) {}
142    Arg(MangledName MN) : Kind(AK_Mangled), String(MN.getName()) {}
143    Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
144    Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
145    Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
146    Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
147
148    ArgKind Kind;
149    union {
150      const char *String;
151      UIntMax UInt;
152      SIntMax SInt;
153      FloatMax Float;
154      const void *Pointer;
155    };
156  };
157
158private:
159  static const unsigned MaxArgs = 5;
160  static const unsigned MaxRanges = 1;
161
162  /// The arguments which have been added to this diagnostic so far.
163  Arg Args[MaxArgs];
164  unsigned NumArgs;
165
166  /// The ranges which have been added to this diagnostic so far.
167  Range Ranges[MaxRanges];
168  unsigned NumRanges;
169
170  Diag &AddArg(Arg A) {
171    CHECK(NumArgs != MaxArgs);
172    Args[NumArgs++] = A;
173    return *this;
174  }
175
176  Diag &AddRange(Range A) {
177    CHECK(NumRanges != MaxRanges);
178    Ranges[NumRanges++] = A;
179    return *this;
180  }
181
182  /// \c Diag objects are not copyable.
183  Diag(const Diag &); // NOT IMPLEMENTED
184  Diag &operator=(const Diag &);
185
186public:
187  Diag(Location Loc, DiagLevel Level, const char *Message)
188    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
189  ~Diag();
190
191  Diag &operator<<(const char *Str) { return AddArg(Str); }
192  Diag &operator<<(MangledName MN) { return AddArg(MN); }
193  Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
194  Diag &operator<<(const void *V) { return AddArg(V); }
195  Diag &operator<<(const TypeDescriptor &V);
196  Diag &operator<<(const Value &V);
197  Diag &operator<<(const Range &R) { return AddRange(R); }
198};
199
200} // namespace __ubsan
201
202#endif // UBSAN_DIAG_H
203