brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · b6f338f Raw
241 lines · cpp
1//===-- Debug.cpp - An easy way to add debug output to your code ----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements a handy way of adding debugging information to your10// code, without it being enabled all of the time, and without having to add11// command line options to enable it.12//13// In particular, just wrap your code with the LLVM_DEBUG() macro, and it will14// be enabled automatically if you specify '-debug' on the command-line.15// Alternatively, you can also use the SET_DEBUG_TYPE("foo") macro to specify16// that your debug code belongs to class "foo".  Then, on the command line, you17// can specify '-debug-only=foo' to enable JUST the debug information for the18// foo class.19//20// When compiling without assertions, the -debug-* options and all code in21// LLVM_DEBUG() statements disappears, so it does not affect the runtime of the22// code.23//24//===----------------------------------------------------------------------===//25 26#include "llvm/Support/Debug.h"27#include "llvm/ADT/StringExtras.h"28#include "llvm/Support/CommandLine.h"29#include "llvm/Support/ManagedStatic.h"30#include "llvm/Support/Signals.h"31#include "llvm/Support/circular_raw_ostream.h"32#include "llvm/Support/raw_ostream.h"33#include <utility>34 35#include "DebugOptions.h"36 37#undef isCurrentDebugType38#undef setCurrentDebugType39#undef setCurrentDebugTypes40 41using namespace llvm;42 43/// Parse a debug type string into a pair of the debug type and the debug level.44/// The expected format is "type[:level]", where the level is an optional45/// integer.46static std::pair<std::string, std::optional<int>>47parseDebugType(StringRef DbgType) {48  std::optional<int> Level;49  size_t ColonPos = DbgType.find(':');50  if (ColonPos != StringRef::npos) {51    StringRef LevelStr = DbgType.substr(ColonPos + 1);52    DbgType = DbgType.take_front(ColonPos);53    if (LevelStr.empty())54      Level = 0;55    else {56      int parsedLevel;57      if (to_integer(LevelStr, parsedLevel, 10))58        Level = parsedLevel;59    }60  }61  return std::make_pair(DbgType.str(), Level);62}63 64// Even though LLVM might be built with NDEBUG, define symbols that the code65// built without NDEBUG can depend on via the llvm/Support/Debug.h header.66namespace llvm {67/// Exported boolean set by the -debug option.68bool DebugFlag = false;69 70/// The current debug type and an optional debug level.71/// The debug level is the verbosity of the debug output.72/// 0 is a special level that acts as an opt-out for this specific debug type.73/// If provided, the debug output is enabled only if the user specified a level74/// at least as high as the provided level.75static ManagedStatic<std::vector<std::pair<std::string, std::optional<int>>>>76    CurrentDebugType;77 78/// Return true if the specified string is the debug type79/// specified on the command line, or if none was specified on the command line80/// with the -debug-only=X option.81bool isCurrentDebugType(const char *DebugType, int Level) {82  if (CurrentDebugType->empty())83    return true;84  // Track if there is at least one debug type with a level, this is used85  // to allow to opt-out of some DebugType and leaving all the others enabled.86  bool HasEnabledDebugType = false;87  // See if DebugType is in list. Note: do not use find() as that forces us to88  // unnecessarily create an std::string instance.89  for (auto &D : *CurrentDebugType) {90    HasEnabledDebugType =91        HasEnabledDebugType || (!D.second.has_value() || D.second.value() > 0);92    if (D.first != DebugType)93      continue;94    if (!D.second.has_value())95      return true;96    return D.second >= Level;97  }98  return !HasEnabledDebugType;99}100 101/// Set the current debug type, as if the -debug-only=X102/// option were specified.  Note that DebugFlag also needs to be set to true for103/// debug output to be produced.104///105void setCurrentDebugTypes(const char **Types, unsigned Count);106 107void setCurrentDebugType(const char *Type) {108  setCurrentDebugTypes(&Type, 1);109}110 111void setCurrentDebugTypes(const char **Types, unsigned Count) {112  CurrentDebugType->clear();113  CurrentDebugType->reserve(Count);114  for (const char *Type : ArrayRef(Types, Count))115    CurrentDebugType->push_back(parseDebugType(Type));116}117 118} // namespace llvm119 120// All Debug.h functionality is a no-op in NDEBUG mode.121#ifndef NDEBUG122 123namespace {124struct CreateDebug {125  static void *call() {126    return new cl::opt<bool, true>("debug", cl::desc("Enable debug output"),127                                   cl::Hidden, cl::location(DebugFlag));128  }129};130 131// -debug-buffer-size - Buffer the last N characters of debug output132//until program termination.133struct CreateDebugBufferSize {134  static void *call() {135    return new cl::opt<unsigned>(136        "debug-buffer-size",137        cl::desc("Buffer the last N characters of debug output "138                 "until program termination. "139                 "[default 0 -- immediate print-out]"),140        cl::Hidden, cl::init(0));141  }142};143} // namespace144 145// -debug - Command line option to enable the DEBUG statements in the passes.146// This flag may only be enabled in debug builds.147static ManagedStatic<cl::opt<bool, true>, CreateDebug> Debug;148static ManagedStatic<cl::opt<unsigned>, CreateDebugBufferSize> DebugBufferSize;149 150namespace {151 152struct DebugOnlyOpt {153  void operator=(const std::string &Val) const {154    if (Val.empty())155      return;156    DebugFlag = true;157    SmallVector<StringRef, 8> DbgTypes;158    StringRef(Val).split(DbgTypes, ',', -1, false);159    for (auto DbgType : DbgTypes)160      CurrentDebugType->push_back(parseDebugType(DbgType));161  }162};163} // namespace164 165static DebugOnlyOpt DebugOnlyOptLoc;166 167namespace {168struct CreateDebugOnly {169  static void *call() {170    return new cl::opt<DebugOnlyOpt, true, cl::parser<std::string>>(171        "debug-only",172        cl::desc(173            "Enable a specific type of debug output (comma separated list "174            "of types using the format \"type[:level]\", where the level "175            "is an optional integer. The level can be set to 1, 2, 3, etc. to "176            "control the verbosity of the output. Setting a debug-type level "177            "to zero acts as an opt-out for this specific debug-type without "178            "affecting the others."),179        cl::Hidden, cl::value_desc("debug string"),180        cl::location(DebugOnlyOptLoc), cl::ValueRequired);181  }182};183} // namespace184 185static ManagedStatic<cl::opt<DebugOnlyOpt, true, cl::parser<std::string>>,186                     CreateDebugOnly>187    DebugOnly;188 189void llvm::initDebugOptions() {190  *Debug;191  *DebugBufferSize;192  *DebugOnly;193}194 195// Signal handlers - dump debug output on termination.196static void debug_user_sig_handler(void *Cookie) {197  // This is a bit sneaky.  Since this is under #ifndef NDEBUG, we198  // know that debug mode is enabled and dbgs() really is a199  // circular_raw_ostream.  If NDEBUG is defined, then dbgs() ==200  // errs() but this will never be invoked.201  llvm::circular_raw_ostream &dbgout =202      static_cast<circular_raw_ostream &>(llvm::dbgs());203  dbgout.flushBufferWithBanner();204}205 206/// dbgs - Return a circular-buffered debug stream.207raw_ostream &llvm::dbgs() {208  // Do one-time initialization in a thread-safe way.209  static struct dbgstream {210    circular_raw_ostream strm;211 212    dbgstream()213        : strm(errs(), "*** Debug Log Output ***\n",214               (!EnableDebugBuffering || !DebugFlag) ? 0 : *DebugBufferSize) {215      if (EnableDebugBuffering && DebugFlag && *DebugBufferSize != 0)216        // TODO: Add a handler for SIGUSER1-type signals so the user can217        // force a debug dump.218        sys::AddSignalHandler(&debug_user_sig_handler, nullptr);219      // Otherwise we've already set the debug stream buffer size to220      // zero, disabling buffering so it will output directly to errs().221    }222  } thestrm;223 224  return thestrm.strm;225}226 227#else228// Avoid "has no symbols" warning.229namespace llvm {230  /// dbgs - Return errs().231  raw_ostream &dbgs() {232    return errs();233  }234}235void llvm::initDebugOptions() {}236#endif237 238/// EnableDebugBuffering - Turn on signal handler installation.239///240bool llvm::EnableDebugBuffering = false;241