mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
231 lines
5.3 KiB
C++
231 lines
5.3 KiB
C++
/* Debugging code for logging what the diagnostics subsystem is doing.
|
|
Copyright (C) 2025-2026 Free Software Foundation, Inc.
|
|
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef GCC_DIAGNOSTICS_LOGGING_H
|
|
#define GCC_DIAGNOSTICS_LOGGING_H
|
|
|
|
#include "diagnostics/output-file.h"
|
|
#include "diagnostics/option-id.h"
|
|
#include "diagnostics/kinds.h"
|
|
|
|
namespace diagnostics {
|
|
|
|
namespace logging {
|
|
|
|
/* A class for emitting a temporal log of what the diagnostics subsystem
|
|
is doing, for debugging.
|
|
We can't use pretty_printer here as we could potentially be debugging
|
|
pretty-printing itself. */
|
|
|
|
class logger
|
|
{
|
|
public:
|
|
logger (output_file outfile);
|
|
|
|
/* High-level functions that emit a line of text. */
|
|
void log_printf (const char *fmt, ...)
|
|
__attribute__ ((__format__ (printf, 2, 3)));
|
|
void log_bool_return (const char *function_name, bool retval);
|
|
|
|
/* Lower-level functions for building up a line of text. */
|
|
void emit_indent () const;
|
|
void emit_newline () const;
|
|
|
|
FILE *get_stream () const
|
|
{
|
|
return m_outfile.get_open_file ();
|
|
}
|
|
|
|
int get_indent () const { return m_log_depth * 2; }
|
|
|
|
void inc_depth () { m_log_depth++; }
|
|
void dec_depth () { m_log_depth--; }
|
|
|
|
private:
|
|
output_file m_outfile;
|
|
int m_log_depth;
|
|
};
|
|
|
|
/* RAII class for pushing/popping depth within a logger. */
|
|
|
|
class auto_inc_depth
|
|
{
|
|
public:
|
|
auto_inc_depth (logger *log)
|
|
: m_logger (log)
|
|
{
|
|
if (m_logger)
|
|
m_logger->inc_depth ();
|
|
}
|
|
~auto_inc_depth ()
|
|
{
|
|
if (m_logger)
|
|
m_logger->dec_depth ();
|
|
}
|
|
|
|
private:
|
|
logger *m_logger;
|
|
};
|
|
|
|
/* Class for debugging function call parameters. */
|
|
|
|
class log_function_params
|
|
{
|
|
public:
|
|
log_function_params (logger *logger_, const char *name)
|
|
: m_logger (logger_),
|
|
m_first_param (true)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
m_logger->emit_indent ();
|
|
fprintf (m_logger->get_stream (), "%s (", name);
|
|
}
|
|
}
|
|
~log_function_params ()
|
|
{
|
|
if (m_logger)
|
|
{
|
|
fprintf (m_logger->get_stream (), ")");
|
|
m_logger->emit_newline ();
|
|
}
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_string (const char *name, const char *value)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (), "%s: \"%s\"", name, value);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_location_t (const char *name, location_t value)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (),
|
|
"%s: " HOST_SIZE_T_PRINT_HEX,
|
|
name, (fmt_size_t)value);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_rich_location (const char *name, const rich_location *richloc)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (),
|
|
"%s: %p",
|
|
name, const_cast<void *> ((const void *)richloc));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_option_id (const char *name, diagnostics::option_id value)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (), "%s: %i", name, value.m_idx);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_kind (const char *name, enum diagnostics::kind value)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (), "%s: %s",
|
|
name, get_debug_string_for_kind (value));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_param_uhwi (const char *name, unsigned HOST_WIDE_INT value)
|
|
{
|
|
if (m_logger)
|
|
{
|
|
add_any_comma ();
|
|
fprintf (m_logger->get_stream (),
|
|
"%s: " HOST_WIDE_INT_PRINT_DEC,
|
|
name, value);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
log_function_params &
|
|
log_params_n_gmsgids (unsigned HOST_WIDE_INT n,
|
|
const char *singular_gmsgid,
|
|
const char *plural_gmsgid)
|
|
{
|
|
return log_param_uhwi ("n", n)
|
|
.log_param_string ("singular_gmsgid", singular_gmsgid)
|
|
.log_param_string ("plural_gmsgid", plural_gmsgid);
|
|
}
|
|
|
|
private:
|
|
void
|
|
add_any_comma ()
|
|
{
|
|
gcc_assert (m_logger);
|
|
if (m_first_param)
|
|
m_first_param = false;
|
|
else
|
|
fprintf (m_logger->get_stream (), ", ");
|
|
}
|
|
|
|
logger *m_logger;
|
|
bool m_first_param;
|
|
};
|
|
|
|
} // namespace logging
|
|
} // namespace diagnostics
|
|
|
|
/* Various macros for logging a formatted line, and indenting
|
|
further log messages within a scope. */
|
|
|
|
#define DIAGNOSTICS_LOG_SCOPE_PRINTF0(LOGGER, FMT) \
|
|
if (LOGGER) \
|
|
(LOGGER)->log_printf ((FMT)); \
|
|
diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
|
|
|
|
#define DIAGNOSTICS_LOG_SCOPE_PRINTF1(LOGGER, FMT, ARG0) \
|
|
if (LOGGER) \
|
|
(LOGGER)->log_printf ((FMT), (ARG0)); \
|
|
diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
|
|
|
|
#define DIAGNOSTICS_LOG_SCOPE_PRINTF2(LOGGER, FMT, ARG0, ARG1) \
|
|
if (LOGGER) \
|
|
(LOGGER)->log_printf ((FMT), (ARG0), (ARG1)); \
|
|
diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
|
|
|
|
#endif /* ! GCC_DIAGNOSTICS_LOGGING_H */
|