1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 00    Debug Routines */
10 
11 #ifndef SQUID_DEBUG_H
12 #define SQUID_DEBUG_H
13 
14 #include "base/Here.h"
15 // XXX should be mem/forward.h once it removes dependencies on typedefs.h
16 #include "mem/AllocatorProxy.h"
17 
18 #include <iostream>
19 #undef assert
20 #include <sstream>
21 #include <iomanip>
22 #if defined(assert)
23 #undef assert
24 #endif
25 
26 #if PURIFY
27 #define assert(EX) ((void)0)
28 #elif defined(NODEBUG)
29 #define assert(EX) ((void)0)
30 #elif STDC_HEADERS
31 #define assert(EX)  ((EX)?((void)0):xassert( # EX , __FILE__, __LINE__))
32 #else
33 #define assert(EX)  ((EX)?((void)0):xassert("EX", __FILE__, __LINE__))
34 #endif
35 
36 /* context-based debugging, the actual type is subject to change */
37 typedef int Ctx;
38 Ctx ctx_enter(const char *descr);
39 void ctx_exit(Ctx ctx);
40 
41 /* defined debug section limits */
42 #define MAX_DEBUG_SECTIONS 100
43 
44 /* defined names for Debug Levels */
45 #define DBG_CRITICAL    0   /**< critical messages always shown when they occur */
46 #define DBG_IMPORTANT   1   /**< important messages always shown when their section is being checked */
47 /* levels 2-8 are still being discussed amongst the developers */
48 #define DBG_DATA    9   /**< output is a large data dump only necessary for advanced debugging */
49 
50 #define DBG_PARSE_NOTE(x) (opt_parse_cfg_only?0:(x)) /**< output is always to be displayed on '-k parse' but at level-x normally. */
51 
52 class Debug
53 {
54 
55 public:
56     /// meta-information for debugs() or a similar debugging call
57     class Context
58     {
59     public:
60         Context(const int aSectionLevel, const int aLevel);
61 
62         int level; ///< minimum debugging level required by the debugs() call
63         int sectionLevel; ///< maximum debugging level allowed during the call
64 
65     private:
66         friend class Debug;
67         void rewind(const int aSection, const int aLevel);
68         void formatStream();
69         Context *upper; ///< previous or parent record in nested debugging calls
70         std::ostringstream buf; ///< debugs() output sink
71         bool forceAlert; ///< the current debugs() will be a syslog ALERT
72     };
73 
74     /// whether debugging the given section and the given level produces output
Enabled(const int section,const int level)75     static bool Enabled(const int section, const int level)
76     {
77         return level <= Debug::Levels[section];
78     }
79 
80     static char *debugOptions;
81     static char *cache_log;
82     static int rotateNumber;
83     static int Levels[MAX_DEBUG_SECTIONS];
84     static int override_X;
85     static int log_stderr;
86     static bool log_syslog;
87 
88     static void parseOptions(char const *);
89 
90     /// minimum level required by the current debugs() call
Level()91     static int Level() { return Current ? Current->level : 1; }
92     /// maximum level currently allowed
SectionLevel()93     static int SectionLevel() { return Current ? Current->sectionLevel : 1; }
94 
95     /// opens debugging context and returns output buffer
96     static std::ostringstream &Start(const int section, const int level);
97     /// logs output buffer created in Start() and closes debugging context
98     static void Finish();
99 
100     /// configures the active debugging context to write syslog ALERT
101     static void ForceAlert();
102 
103     /// prefixes each grouped debugs() line after the first one in the group
Extra(std::ostream & os)104     static std::ostream& Extra(std::ostream &os) { return os << "\n    "; }
105 
106 private:
107     static Context *Current; ///< deepest active context; nil outside debugs()
108 };
109 
110 /// cache.log FILE or, as the last resort, stderr stream;
111 /// may be nil during static initialization and destruction!
112 FILE *DebugStream();
113 /// change-avoidance macro; new code should call DebugStream() instead
114 #define debug_log DebugStream()
115 
116 /// start logging to stderr (instead of cache.log, if any)
117 void StopUsingDebugLog();
118 
119 /// a hack for low-level file descriptor manipulations in ipcCreate()
120 void ResyncDebugLog(FILE *newDestination);
121 
122 /* Debug stream
123  *
124  * Unit tests can enable full debugging to stderr for one
125  * debug section; to enable this, #define ENABLE_DEBUG_SECTION to the
126  * section number before any header
127  */
128 #define debugs(SECTION, LEVEL, CONTENT) \
129    do { \
130         const int _dbg_level = (LEVEL); \
131         if (Debug::Enabled((SECTION), _dbg_level)) { \
132             std::ostream &_dbo = Debug::Start((SECTION), _dbg_level); \
133             if (_dbg_level > DBG_IMPORTANT) { \
134                 _dbo << (SECTION) << ',' << _dbg_level << "| " \
135                      << Here() << ": "; \
136             } \
137             _dbo << CONTENT; \
138             Debug::Finish(); \
139         } \
140    } while (/*CONSTCOND*/ 0)
141 
142 /// Does not change the stream being manipulated. Exists for its side effect:
143 /// In a debugs() context, forces the message to become a syslog ALERT.
144 /// Outside of debugs() context, has no effect and should not be used.
145 std::ostream& ForceAlert(std::ostream& s);
146 
147 /** stream manipulator which does nothing.
148  * \deprecated Do not add to new code, and remove when editing old code
149  *
150  * Its purpose is to inactivate calls made following previous debugs()
151  * guidelines such as
152  * debugs(1,2, HERE << "some message");
153  *
154  * His former objective is now absorbed in the debugs call itself
155  */
156 inline std::ostream&
HERE(std::ostream & s)157 HERE(std::ostream& s)
158 {
159     return s;
160 }
161 
162 /*
163  * MYNAME is for use at debug levels 0 and 1 where HERE is too messy.
164  *
165  * debugs(1,1, MYNAME << "WARNING: some message");
166  */
167 #ifdef __PRETTY_FUNCTION__
168 #define MYNAME __PRETTY_FUNCTION__ << " "
169 #else
170 #define MYNAME __FUNCTION__ << " "
171 #endif
172 
173 /* some uint8_t do not like streaming control-chars (values 0-31, 127+) */
174 inline std::ostream& operator <<(std::ostream &os, const uint8_t d)
175 {
176     return (os << (int)d);
177 }
178 
179 /* Legacy debug function definitions */
180 void _db_init(const char *logfile, const char *options);
181 void _db_set_syslog(const char *facility);
182 void _db_rotate_log(void);
183 
184 /// Prints raw and/or non-terminated data safely, efficiently, and beautifully.
185 /// Allows raw data debugging in debugs() statements with low debugging levels
186 /// by printing only if higher section debugging levels are configured:
187 ///   debugs(11, DBG_IMPORTANT, "always printed" << Raw(may be printed...));
188 class Raw
189 {
190 public:
Raw(const char * label,const char * data,const size_t size)191     Raw(const char *label, const char *data, const size_t size):
192         level(-1), label_(label), data_(data), size_(size), useHex_(false) {}
193 
194     /// limit data printing to at least the given debugging level
minLevel(const int aLevel)195     Raw &minLevel(const int aLevel) { level = aLevel; return *this; }
196 
197     /// print data using two hex digits per byte (decoder: xxd -r -p)
hex()198     Raw &hex() { useHex_ = true; return *this; }
199 
200     /// If debugging is prohibited by the current debugs() or section level,
201     /// prints nothing. Otherwise, dumps data using one of these formats:
202     ///   " label[size]=data" if label was set and data size is positive
203     ///   " label[0]" if label was set and data size is zero
204     ///   " data" if label was not set and data size is positive
205     ///   "" (i.e., prints nothing) if label was not set and data size is zero
206     std::ostream &print(std::ostream &os) const;
207 
208     /// Minimum section debugging level necessary for printing. By default,
209     /// small strings are always printed while large strings are only printed
210     /// if DBG_DATA debugging level is enabled.
211     int level;
212 
213 private:
214     void printHex(std::ostream &os) const;
215 
216     const char *label_; ///< optional data name or ID; triggers size printing
217     const char *data_; ///< raw data to be printed
218     size_t size_; ///< data length
219     bool useHex_; ///< whether hex() has been called
220 };
221 
222 inline
223 std::ostream &operator <<(std::ostream &os, const Raw &raw)
224 {
225     return raw.print(os);
226 }
227 
228 /// debugs objects pointed by possibly nil pointers: label=object
229 template <class Pointer>
230 class RawPointerT {
231 public:
RawPointerT(const char * aLabel,const Pointer & aPtr)232     RawPointerT(const char *aLabel, const Pointer &aPtr):
233         label(aLabel), ptr(aPtr) {}
234     const char *label; /// the name or description of the being-debugged object
235     const Pointer &ptr; /// a possibly nil pointer to the being-debugged object
236 };
237 
238 /// convenience wrapper for creating  RawPointerT<> objects
239 template <class Pointer>
240 inline RawPointerT<Pointer>
RawPointer(const char * label,const Pointer & ptr)241 RawPointer(const char *label, const Pointer &ptr)
242 {
243     return RawPointerT<Pointer>(label, ptr);
244 }
245 
246 /// prints RawPointerT<>, dereferencing the raw pointer if possible
247 template <class Pointer>
248 inline std::ostream &
249 operator <<(std::ostream &os, const RawPointerT<Pointer> &pd)
250 {
251     os << pd.label << '=';
252     if (pd.ptr)
253         return os << *pd.ptr;
254     else
255         return os << "[nil]";
256 }
257 
258 /// std::ostream manipulator to print integers as hex numbers prefixed by 0x
259 template <class Integer>
260 class AsHex
261 {
262 public:
AsHex(const Integer n)263     explicit AsHex(const Integer n): raw(n) {}
264     Integer raw; ///< the integer to print
265 };
266 
267 template <class Integer>
268 inline std::ostream &
269 operator <<(std::ostream &os, const AsHex<Integer> number)
270 {
271     const auto oldFlags = os.flags();
272     os << std::hex << std::showbase << number.raw;
273     os.setf(oldFlags);
274     return os;
275 }
276 
277 /// a helper to ease AsHex object creation
278 template <class Integer>
asHex(const Integer n)279 inline AsHex<Integer> asHex(const Integer n) { return AsHex<Integer>(n); }
280 
281 #endif /* SQUID_DEBUG_H */
282 
283