hb-debug.hh (12077B)
1 /* 2 * Copyright © 2017 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #ifndef HB_DEBUG_HH 28 #define HB_DEBUG_HH 29 30 #include "hb.hh" 31 #include "hb-atomic.hh" 32 #include "hb-algs.hh" 33 34 35 #ifndef HB_DEBUG 36 #define HB_DEBUG 0 37 #endif 38 39 40 /* 41 * Debug output (needs enabling at compile time.) 42 */ 43 44 static inline bool 45 _hb_debug (unsigned int level, 46 unsigned int max_level) 47 { 48 return level < max_level; 49 } 50 51 #define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT)) 52 #define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0)) 53 54 static inline void 55 _hb_print_func (const char *func) 56 { 57 if (func) 58 { 59 unsigned int func_len = strlen (func); 60 /* Skip "static" */ 61 if (0 == strncmp (func, "static ", 7)) 62 func += 7; 63 /* Skip "typename" */ 64 if (0 == strncmp (func, "typename ", 9)) 65 func += 9; 66 /* Skip return type */ 67 const char *space = strchr (func, ' '); 68 if (space) 69 func = space + 1; 70 /* Skip parameter list */ 71 const char *paren = strchr (func, '('); 72 if (paren) 73 func_len = paren - func; 74 fprintf (stderr, "%.*s", (int) func_len, func); 75 } 76 } 77 78 template <int max_level> static inline void 79 _hb_debug_msg_va (const char *what, 80 const void *obj, 81 const char *func, 82 bool indented, 83 unsigned int level, 84 int level_dir, 85 const char *message, 86 va_list ap) HB_PRINTF_FUNC(7, 0); 87 template <int max_level> static inline void 88 _hb_debug_msg_va (const char *what, 89 const void *obj, 90 const char *func, 91 bool indented, 92 unsigned int level, 93 int level_dir, 94 const char *message, 95 va_list ap) 96 { 97 if (!_hb_debug (level, max_level)) 98 return; 99 100 fprintf (stderr, "%-10s", what ? what : ""); 101 102 if (obj) 103 fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj); 104 else 105 fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), ""); 106 107 if (indented) { 108 #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ 109 #define VRBAR "\342\224\234" /* U+251C BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ 110 #define DLBAR "\342\225\256" /* U+256E BOX DRAWINGS LIGHT ARC DOWN AND LEFT */ 111 #define ULBAR "\342\225\257" /* U+256F BOX DRAWINGS LIGHT ARC UP AND LEFT */ 112 #define LBAR "\342\225\264" /* U+2574 BOX DRAWINGS LIGHT LEFT */ 113 static const char bars[] = 114 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR 115 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR 116 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR 117 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR 118 VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR; 119 fprintf (stderr, "%2u %s" VRBAR "%s", 120 level, 121 bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level), 122 level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR); 123 } else 124 fprintf (stderr, " " VRBAR LBAR); 125 126 _hb_print_func (func); 127 128 if (message) 129 { 130 fprintf (stderr, ": "); 131 vfprintf (stderr, message, ap); 132 } 133 134 fprintf (stderr, "\n"); 135 } 136 template <> inline void HB_PRINTF_FUNC(7, 0) 137 _hb_debug_msg_va<0> (const char *what HB_UNUSED, 138 const void *obj HB_UNUSED, 139 const char *func HB_UNUSED, 140 bool indented HB_UNUSED, 141 unsigned int level HB_UNUSED, 142 int level_dir HB_UNUSED, 143 const char *message HB_UNUSED, 144 va_list ap HB_UNUSED) {} 145 146 template <int max_level> static inline void 147 _hb_debug_msg (const char *what, 148 const void *obj, 149 const char *func, 150 bool indented, 151 unsigned int level, 152 int level_dir, 153 const char *message, 154 ...) HB_PRINTF_FUNC(7, 8); 155 template <int max_level> static inline void HB_PRINTF_FUNC(7, 8) 156 _hb_debug_msg (const char *what, 157 const void *obj, 158 const char *func, 159 bool indented, 160 unsigned int level, 161 int level_dir, 162 const char *message, 163 ...) 164 { 165 va_list ap; 166 va_start (ap, message); 167 _hb_debug_msg_va<max_level> (what, obj, func, indented, level, level_dir, message, ap); 168 va_end (ap); 169 } 170 template <> inline void 171 _hb_debug_msg<0> (const char *what HB_UNUSED, 172 const void *obj HB_UNUSED, 173 const char *func HB_UNUSED, 174 bool indented HB_UNUSED, 175 unsigned int level HB_UNUSED, 176 int level_dir HB_UNUSED, 177 const char *message HB_UNUSED, 178 ...) HB_PRINTF_FUNC(7, 8); 179 template <> inline void HB_PRINTF_FUNC(7, 8) 180 _hb_debug_msg<0> (const char *what HB_UNUSED, 181 const void *obj HB_UNUSED, 182 const char *func HB_UNUSED, 183 bool indented HB_UNUSED, 184 unsigned int level HB_UNUSED, 185 int level_dir HB_UNUSED, 186 const char *message HB_UNUSED, 187 ...) {} 188 189 #define DEBUG_MSG_LEVEL(WHAT, OBJ, LEVEL, LEVEL_DIR, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, true, (LEVEL), (LEVEL_DIR), __VA_ARGS__) 190 #define DEBUG_MSG(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), nullptr, false, 0, 0, __VA_ARGS__) 191 #define DEBUG_MSG_FUNC(WHAT, OBJ, ...) _hb_debug_msg<HB_DEBUG_##WHAT> (#WHAT, (OBJ), HB_FUNC, false, 0, 0, __VA_ARGS__) 192 193 194 /* 195 * Printer 196 */ 197 198 template <typename T> 199 struct hb_printer_t { 200 const char *print (const T&) { return "something"; } 201 }; 202 203 template <> 204 struct hb_printer_t<bool> { 205 const char *print (bool v) { return v ? "true" : "false"; } 206 }; 207 208 template <> 209 struct hb_printer_t<hb_empty_t> { 210 const char *print (hb_empty_t) { return ""; } 211 }; 212 213 214 /* 215 * Trace 216 */ 217 218 template <typename T> 219 static inline void _hb_warn_no_return (bool returned) 220 { 221 if (unlikely (!returned)) { 222 fprintf (stderr, "OUCH, returned with no call to return_trace(). This is a bug, please report.\n"); 223 } 224 } 225 template <> 226 /*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED) {} 227 template <> 228 /*static*/ inline void _hb_warn_no_return<void> (bool returned HB_UNUSED) {} 229 230 template <int max_level, typename ret_t> 231 struct hb_auto_trace_t 232 { 233 explicit inline hb_auto_trace_t (unsigned int *plevel_, 234 const char *what_, 235 const void *obj_, 236 const char *func, 237 const char *message, 238 ...) HB_PRINTF_FUNC(6, 7) 239 : plevel (plevel_), what (what_), obj (obj_), returned (false) 240 { 241 if (plevel) ++*plevel; 242 243 va_list ap; 244 va_start (ap, message); 245 _hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap); 246 va_end (ap); 247 } 248 ~hb_auto_trace_t () 249 { 250 _hb_warn_no_return<ret_t> (returned); 251 if (!returned) { 252 _hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1, " "); 253 } 254 if (plevel) --*plevel; 255 } 256 257 template <typename T> 258 T ret (T&& v, 259 const char *func = "", 260 unsigned int line = 0) 261 { 262 if (unlikely (returned)) { 263 fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n"); 264 return std::forward<T> (v); 265 } 266 267 _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1, 268 "return %s (line %u)", 269 hb_printer_t<hb_decay<decltype (v)>>().print (v), line); 270 if (plevel) --*plevel; 271 plevel = nullptr; 272 returned = true; 273 return std::forward<T> (v); 274 } 275 276 private: 277 unsigned int *plevel; 278 const char *what; 279 const void *obj; 280 bool returned; 281 }; 282 template <typename ret_t> /* Make sure we don't use hb_auto_trace_t when not tracing. */ 283 struct hb_auto_trace_t<0, ret_t> 284 { 285 explicit inline hb_auto_trace_t (unsigned int *plevel_, 286 const char *what_, 287 const void *obj_, 288 const char *func, 289 const char *message, 290 ...) HB_PRINTF_FUNC(6, 7) {} 291 292 template <typename T> 293 T ret (T&& v, 294 const char *func HB_UNUSED = nullptr, 295 unsigned int line HB_UNUSED = 0) { return std::forward<T> (v); } 296 }; 297 298 /* For disabled tracing; optimize out everything. 299 * https://github.com/harfbuzz/harfbuzz/pull/605 */ 300 template <typename ret_t> 301 struct hb_no_trace_t { 302 template <typename T> 303 T ret (T&& v, 304 const char *func HB_UNUSED = nullptr, 305 unsigned int line HB_UNUSED = 0) { return std::forward<T> (v); } 306 }; 307 308 #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__) 309 310 311 /* 312 * Instances. 313 */ 314 315 #ifndef HB_DEBUG_ARABIC 316 #define HB_DEBUG_ARABIC (HB_DEBUG+0) 317 #endif 318 319 #ifndef HB_DEBUG_BLOB 320 #define HB_DEBUG_BLOB (HB_DEBUG+0) 321 #endif 322 323 #ifndef HB_DEBUG_CORETEXT 324 #define HB_DEBUG_CORETEXT (HB_DEBUG+0) 325 #endif 326 327 #ifndef HB_DEBUG_DIRECTWRITE 328 #define HB_DEBUG_DIRECTWRITE (HB_DEBUG+0) 329 #endif 330 331 #ifndef HB_DEBUG_FT 332 #define HB_DEBUG_FT (HB_DEBUG+0) 333 #endif 334 335 #ifndef HB_DEBUG_JUSTIFY 336 #define HB_DEBUG_JUSTIFY (HB_DEBUG+0) 337 #endif 338 339 #ifndef HB_DEBUG_OBJECT 340 #define HB_DEBUG_OBJECT (HB_DEBUG+0) 341 #endif 342 343 #ifndef HB_DEBUG_SHAPE_PLAN 344 #define HB_DEBUG_SHAPE_PLAN (HB_DEBUG+0) 345 #endif 346 347 #ifndef HB_DEBUG_UNISCRIBE 348 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0) 349 #endif 350 351 #ifndef HB_DEBUG_WASM 352 #define HB_DEBUG_WASM (HB_DEBUG+0) 353 #endif 354 355 #ifndef HB_DEBUG_KBTS 356 #define HB_DEBUG_KBTS (HB_DEBUG+0) 357 #endif 358 359 /* 360 * With tracing. 361 */ 362 363 #ifndef HB_DEBUG_APPLY 364 #define HB_DEBUG_APPLY (HB_DEBUG+0) 365 #endif 366 #if HB_DEBUG_APPLY 367 #define TRACE_APPLY(this) \ 368 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ 369 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 370 "idx %u gid %u lookup %d", \ 371 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) 372 #else 373 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace 374 #endif 375 376 #ifndef HB_DEBUG_SANITIZE 377 #define HB_DEBUG_SANITIZE (HB_DEBUG+0) 378 #endif 379 #if HB_DEBUG_SANITIZE 380 #define TRACE_SANITIZE(this) \ 381 hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \ 382 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 383 " ") 384 #else 385 #define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace 386 #endif 387 388 #ifndef HB_DEBUG_SERIALIZE 389 #define HB_DEBUG_SERIALIZE (HB_DEBUG+0) 390 #endif 391 #if HB_DEBUG_SERIALIZE 392 #define TRACE_SERIALIZE(this) \ 393 hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \ 394 (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ 395 " ") 396 #else 397 #define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace 398 #endif 399 400 #ifndef HB_DEBUG_SUBSET 401 #define HB_DEBUG_SUBSET (HB_DEBUG+0) 402 #endif 403 #if HB_DEBUG_SUBSET 404 #define TRACE_SUBSET(this) \ 405 hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \ 406 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 407 " ") 408 #else 409 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace 410 #endif 411 412 #ifndef HB_DEBUG_SUBSET_REPACK 413 #define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0) 414 #endif 415 416 #ifndef HB_DEBUG_PAINT 417 #define HB_DEBUG_PAINT (HB_DEBUG+0) 418 #endif 419 #if HB_DEBUG_PAINT 420 #define TRACE_PAINT(this) \ 421 HB_UNUSED hb_auto_trace_t<HB_DEBUG_PAINT, void> trace \ 422 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 423 " ") 424 #else 425 #define TRACE_PAINT(this) HB_UNUSED hb_no_trace_t<void> trace 426 #endif 427 428 429 #ifndef HB_DEBUG_DISPATCH 430 #define HB_DEBUG_DISPATCH ( \ 431 HB_DEBUG_APPLY + \ 432 HB_DEBUG_SANITIZE + \ 433 HB_DEBUG_SERIALIZE + \ 434 HB_DEBUG_SUBSET + \ 435 HB_DEBUG_PAINT + \ 436 0) 437 #endif 438 #if HB_DEBUG_DISPATCH 439 #define TRACE_DISPATCH(this, format) \ 440 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ 441 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 442 "format %u", (unsigned) format) 443 #else 444 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace 445 #endif 446 447 448 #ifndef HB_BUFFER_MESSAGE_MORE 449 #define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+0) 450 #endif 451 452 453 #endif /* HB_DEBUG_HH */