ubsan_diag.h revision 25ee97fe8ada76755c8bd1087fac9cc3cd03b28c
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 Representation of an in-flight diagnostic.
104///
105/// Temporary \c Diag instances are created by the handler routines to
106/// accumulate arguments for a diagnostic. The destructor emits the diagnostic
107/// message.
108class Diag {
109  /// The location at which the problem occurred.
110  Location Loc;
111
112  /// The diagnostic level.
113  DiagLevel Level;
114
115  /// The message which will be emitted, with %0, %1, ... placeholders for
116  /// arguments.
117  const char *Message;
118
119public:
120  /// Kinds of arguments, corresponding to members of \c Arg's union.
121  enum ArgKind {
122    AK_String, ///< A string argument, displayed as-is.
123    AK_UInt,   ///< An unsigned integer argument.
124    AK_SInt,   ///< A signed integer argument.
125    AK_Float,  ///< A floating-point argument.
126    AK_Pointer ///< A pointer argument, displayed in hexadecimal.
127  };
128
129  /// An individual diagnostic message argument.
130  struct Arg {
131    Arg() {}
132    Arg(const char *String) : Kind(AK_String), String(String) {}
133    Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
134    Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
135    Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
136    Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
137
138    ArgKind Kind;
139    union {
140      const char *String;
141      UIntMax UInt;
142      SIntMax SInt;
143      FloatMax Float;
144      const void *Pointer;
145    };
146  };
147
148private:
149  static const unsigned MaxArgs = 5;
150  static const unsigned MaxRanges = 1;
151
152  /// The arguments which have been added to this diagnostic so far.
153  Arg Args[MaxArgs];
154  unsigned NumArgs;
155
156  /// The ranges which have been added to this diagnostic so far.
157  Range Ranges[MaxRanges];
158  unsigned NumRanges;
159
160  Diag &AddArg(Arg A) {
161    CHECK(NumArgs != MaxArgs);
162    Args[NumArgs++] = A;
163    return *this;
164  }
165
166  Diag &AddRange(Range A) {
167    CHECK(NumRanges != MaxRanges);
168    Ranges[NumRanges++] = A;
169    return *this;
170  }
171
172  /// \c Diag objects are not copyable.
173  Diag(const Diag &); // NOT IMPLEMENTED
174  Diag &operator=(const Diag &);
175
176public:
177  Diag(Location Loc, DiagLevel Level, const char *Message)
178    : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
179  ~Diag();
180
181  Diag &operator<<(const char *Str) { return AddArg(Str); }
182  Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
183  Diag &operator<<(const void *V) { return AddArg(V); }
184  Diag &operator<<(const TypeDescriptor &V);
185  Diag &operator<<(const Value &V);
186  Diag &operator<<(const Range &R) { return AddRange(R); }
187};
188
189} // namespace __ubsan
190
191#endif // UBSAN_DIAG_H
192