text-art/styled-string.o \
text-art/table.o \
text-art/theme.o \
+ text-art/tree-widget.o \
text-art/widget.o
# Objects in libcommon-target.a, used by drivers and by the core
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
return range_obj;
}
+std::unique_ptr<text_art::widget>
+bounded_range::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ return tree_widget::from_fmt (dwi, default_tree_printer,
+ "%qE ... %qE", m_lower, m_upper);
+}
+
/* Subroutine of bounded_range::to_json. */
void
return arr_obj;
}
+void
+bounded_ranges::add_to_dump_widget (text_art::tree_widget &parent,
+ const text_art::dump_widget_info &dwi) const
+{
+ for (auto &range : m_ranges)
+ parent.add_child (range.make_dump_widget (dwi));
+}
+
/* Determine whether (X OP RHS_CONST) is known to be true or false
for all X in the ranges expressed by this object. */
return ec_obj;
}
+std::unique_ptr<text_art::widget>
+equiv_class::make_dump_widget (const text_art::dump_widget_info &dwi,
+ unsigned id) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> ec_widget;
+
+ {
+ pretty_printer pp;
+ pp_string (&pp, "Equivalence class ");
+ equiv_class_id (id).print (&pp);
+ ec_widget = tree_widget::make (dwi, &pp);
+ }
+
+ for (const svalue *sval : m_vars)
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ sval->dump_to_pp (&pp, true);
+ ec_widget->add_child (tree_widget::make (dwi, &pp));
+ }
+
+ if (m_constant)
+ {
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_printf (&pp, "%qE", m_constant);
+ ec_widget->add_child (tree_widget::make (dwi, &pp));
+ }
+
+ return ec_widget;
+}
+
/* Generate a hash value for this equiv_class.
This relies on the ordering of m_vars, and so this object needs to
have been canonicalized for this to be meaningful. */
return con_obj;
}
+std::unique_ptr<text_art::widget>
+constraint::make_dump_widget (const text_art::dump_widget_info &dwi,
+ const constraint_manager &cm) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = true;
+ print (&pp, cm);
+ return text_art::tree_widget::make (dwi, &pp);
+}
+
/* Generate a hash value for this constraint. */
hashval_t
return con_obj;
}
+std::unique_ptr<text_art::widget>
+bounded_ranges_constraint::
+make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> brc_widget
+ (tree_widget::from_fmt (dwi, nullptr,
+ "ec%i bounded ranges", m_ec_id.as_int ()));
+ m_ranges->add_to_dump_widget (*brc_widget.get (), dwi);
+ return brc_widget;
+}
+
bool
bounded_ranges_constraint::
operator== (const bounded_ranges_constraint &other) const
return cm_obj;
}
+std::unique_ptr<text_art::widget>
+constraint_manager::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> cm_widget
+ (tree_widget::make (dwi, "Constraints"));
+
+ /* Equivalence classes. */
+ unsigned i;
+ equiv_class *ec;
+ FOR_EACH_VEC_ELT (m_equiv_classes, i, ec)
+ cm_widget->add_child (ec->make_dump_widget (dwi, i));
+
+ /* Constraints. */
+ for (const constraint &c : m_constraints)
+ cm_widget->add_child (c.make_dump_widget (dwi, *this));
+
+ /* m_bounded_ranges_constraints. */
+ for (const auto &brc : m_bounded_ranges_constraints)
+ cm_widget->add_child (brc.make_dump_widget (dwi));
+
+ if (cm_widget->get_num_children () == 0)
+ return nullptr;
+
+ return cm_widget;
+}
+
/* Attempt to add the constraint LHS OP RHS to this constraint_manager.
Return true if the constraint could be added (or is already true).
Return false if the constraint contradicts existing knowledge. */
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
bool contains_p (tree cst) const;
bool intersects_p (const bounded_range &other,
json::value *to_json () const;
+ void add_to_dump_widget (text_art::tree_widget &parent,
+ const text_art::dump_widget_info &dwi) const;
+
tristate eval_condition (enum tree_code op,
tree rhs_const,
bounded_ranges_manager *mgr) const;
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ unsigned id) const;
+
bool contains_non_constant_p () const;
/* An equivalence class can contain multiple constants (e.g. multiple
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ const constraint_manager &cm) const;
+
hashval_t hash () const;
bool operator== (const constraint &other) const;
void add_to_hash (inchash::hash *hstate) const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
equiv_class_id m_ec_id;
const bounded_ranges *m_ranges;
};
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
const equiv_class &get_equiv_class_by_index (unsigned idx) const
{
return *m_equiv_classes[idx];
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "tree-dfa.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/call-summary.h"
+#include "text-art/dump.h"
/* For an overview, see gcc/doc/analyzer.texi. */
pp_printf (pp, "setjmp_svalue(EN%i)", get_enode_index ());
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ setjmp_svalue. */
+
+void
+setjmp_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "setjmp_svalue(EN: %i)", get_enode_index ());
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ setjmp_svalue. */
+
+void
+setjmp_svalue::
+add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* No children. */
+}
+
/* Get the index of the stored exploded_node. */
int
pretty_printer pp;
enode->get_point ().print (&pp, format (true));
fprintf (outf, "%s\n", pp_formatted_text (&pp));
- enode->get_state ().dump_to_file (m_ext_state, false, true, outf);
+ text_art::dump_to_file (enode->get_state (), outf);
}
fclose (outf);
= xasprintf ("%s.en-%i.txt", dump_base_name, i);
FILE *outf = fopen (filename, "w");
if (!outf)
- error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
+ error_at (UNKNOWN_LOCATION, "unable to open %qs for writing",
+ filename);
free (filename);
fprintf (outf, "EN %i:\n", enode->m_index);
pretty_printer pp;
enode->get_point ().print (&pp, format (true));
fprintf (outf, "%s\n", pp_formatted_text (&pp));
- enode->get_state ().dump_to_file (m_ext_state, false, true, outf);
+ text_art::dump_to_file (enode->get_state (), outf);
fclose (outf);
}
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "analyzer/state-purge.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
+#include "text-art/tree-widget.h"
+#include "text-art/dump.h"
#if ENABLE_ANALYZER
return map_obj;
}
+/* Make a text_art::tree_widget describing this sm_state_map,
+ using MODEL if non-null to describe svalues. */
+
+std::unique_ptr<text_art::widget>
+sm_state_map::make_dump_widget (const text_art::dump_widget_info &dwi,
+ const region_model *model) const
+{
+ using text_art::styled_string;
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> state_widget
+ (tree_widget::from_fmt (dwi, nullptr,
+ "%qs state machine", m_sm.get_name ()));
+
+ if (m_global_state != m_sm.get_start_state ())
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_string (pp, "Global State: ");
+ m_global_state->dump_to_pp (pp);
+ state_widget->add_child (tree_widget::make (dwi, pp));
+ }
+
+ auto_vec <const svalue *> keys (m_map.elements ());
+ for (map_t::iterator iter = m_map.begin ();
+ iter != m_map.end ();
+ ++iter)
+ keys.quick_push ((*iter).first);
+ keys.qsort (svalue::cmp_ptr_ptr);
+ unsigned i;
+ const svalue *sval;
+ FOR_EACH_VEC_ELT (keys, i, sval)
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ const bool simple = true;
+ pp_format_decoder (pp) = default_tree_printer;
+ if (!flag_dump_noaddr)
+ {
+ pp_pointer (pp, sval);
+ pp_string (pp, ": ");
+ }
+ sval->dump_to_pp (pp, simple);
+
+ entry_t e = *const_cast <map_t &> (m_map).get (sval);
+ pp_string (pp, ": ");
+ e.m_state->dump_to_pp (pp);
+ if (model)
+ if (tree rep = model->get_representative_tree (sval))
+ {
+ pp_string (pp, " (");
+ dump_quoted_tree (pp, rep);
+ pp_character (pp, ')');
+ }
+ if (e.m_origin)
+ {
+ pp_string (pp, " (origin: ");
+ if (!flag_dump_noaddr)
+ {
+ pp_pointer (pp, e.m_origin);
+ pp_string (pp, ": ");
+ }
+ e.m_origin->dump_to_pp (pp, simple);
+ if (model)
+ if (tree rep = model->get_representative_tree (e.m_origin))
+ {
+ pp_string (pp, " (");
+ dump_quoted_tree (pp, rep);
+ pp_character (pp, ')');
+ }
+ pp_string (pp, ")");
+ }
+
+ state_widget->add_child (tree_widget::make (dwi, pp));
+ }
+
+ return state_widget;
+}
+
/* Return true if no states have been set within this map
(all expressions are for the start state). */
dump_to_file (ext_state, summarize, true, stderr);
}
+/* Dump a tree-like representation of this state to stderr. */
+
+DEBUG_FUNCTION void
+program_state::dump () const
+{
+ text_art::dump (*this);
+}
+
/* Return a new json::object of the form
{"store" : object for store,
"constraints" : object for constraint_manager,
return state_obj;
}
+
+std::unique_ptr<text_art::widget>
+program_state::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> state_widget
+ (tree_widget::from_fmt (dwi, nullptr, "State"));
+
+ state_widget->add_child (m_region_model->make_dump_widget (dwi));
+
+ /* Add nodes for any sm_state_maps with state. */
+ {
+ int i;
+ sm_state_map *smap;
+ FOR_EACH_VEC_ELT (m_checker_states, i, smap)
+ if (!smap->is_empty_p ())
+ state_widget->add_child (smap->make_dump_widget (dwi, m_region_model));
+ }
+
+ return state_widget;
+}
+
/* Update this program_state to reflect a top-level call to FUN.
The params will have initial_svalues. */
#ifndef GCC_ANALYZER_PROGRAM_STATE_H
#define GCC_ANALYZER_PROGRAM_STATE_H
+#include "text-art/widget.h"
+
namespace ana {
/* Data shared by all program_state instances. */
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ const region_model *model) const;
+
bool is_empty_p () const;
hashval_t hash () const;
void dump_to_file (const extrinsic_state &ext_state, bool simple,
bool multiline, FILE *outf) const;
void dump (const extrinsic_state &ext_state, bool simple) const;
+ void dump () const;
json::object *to_json (const extrinsic_state &ext_state) const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
void push_frame (const extrinsic_state &ext_state, const function &fun);
const function * get_current_function () const;
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
#define INCLUDE_ALGORITHM
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "analyzer/feasible-graph.h"
#include "analyzer/record-layout.h"
#include "diagnostic-format-sarif.h"
+#include "text-art/tree-widget.h"
#if ENABLE_ANALYZER
return map_obj;
}
+std::unique_ptr<text_art::widget>
+region_to_value_map::
+make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ if (is_empty ())
+ return nullptr;
+
+ std::unique_ptr<text_art::tree_widget> w
+ (text_art::tree_widget::make (dwi, "Dynamic Extents"));
+
+ auto_vec<const region *> regs;
+ for (iterator iter = begin (); iter != end (); ++iter)
+ regs.safe_push ((*iter).first);
+ regs.qsort (region::cmp_ptr_ptr);
+
+ unsigned i;
+ const region *reg;
+ FOR_EACH_VEC_ELT (regs, i, reg)
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ const bool simple = true;
+
+ reg->dump_to_pp (pp, simple);
+ pp_string (pp, ": ");
+ const svalue *sval = *get (reg);
+ sval->dump_to_pp (pp, true);
+ w->add_child (text_art::tree_widget::make (dwi, pp));
+ }
+ return w;
+}
+
/* Attempt to merge THIS with OTHER, writing the result
to OUT.
dump (stderr, simple, true);
}
+/* Dump a tree-like representation of this state to stderr. */
+
+DEBUG_FUNCTION void
+region_model::dump () const
+{
+ text_art::dump (*this);
+}
+
/* Dump a multiline representation of this model to stderr. */
DEBUG_FUNCTION void
return model_obj;
}
+std::unique_ptr<text_art::widget>
+region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> model_widget
+ (tree_widget::from_fmt (dwi, nullptr, "Region Model"));
+
+ if (m_current_frame)
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_show_color (pp) = true;
+ const bool simple = true;
+
+ pp_string (pp, "Current Frame: ");
+ m_current_frame->dump_to_pp (pp, simple);
+ model_widget->add_child (tree_widget::make (dwi, pp));
+ }
+ model_widget->add_child
+ (m_store.make_dump_widget (dwi,
+ m_mgr->get_store_manager ()));
+ model_widget->add_child (m_constraints->make_dump_widget (dwi));
+ model_widget->add_child (m_dynamic_extents.make_dump_widget (dwi));
+ return model_widget;
+}
+
/* Assert that this object is valid. */
void
"constraint_manager:\n"
" equiv classes:\n"
" constraints:\n");
+
+ text_art::ascii_theme theme;
+ pretty_printer pp;
+ dump_to_pp (model, &theme, &pp);
+ ASSERT_STREQ ("Region Model\n"
+ "`- Store\n"
+ " `- m_called_unknown_fn: false\n",
+ pp_formatted_text (&pp));
}
/* Helper function for selftests. Create a struct or union type named NAME,
#include "analyzer/known-function-manager.h"
#include "analyzer/region-model-manager.h"
#include "analyzer/pending-diagnostic.h"
+#include "text-art/widget.h"
+#include "text-art/dump.h"
using namespace ana;
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
bool can_merge_with_p (const region_to_value_map &other,
region_to_value_map *out) const;
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
void dump (FILE *fp, bool simple, bool multiline) const;
void dump (bool simple) const;
+ void dump () const;
void debug () const;
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
void validate () const;
void canonicalize ();
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "analyzer/region-model.h"
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
+#include "text-art/dump.h"
#if ENABLE_ANALYZER
pp_flush (&pp);
}
+/* Dump a tree-like representation of this region and its constituent symbols
+ to stderr, using global_dc's colorization and theming options.
+
+ For example:
+ . (gdb) call reg->dump()
+ . (26): ‘int’: decl_region(‘x_10(D)’)
+ . ╰─ parent: (9): frame_region(‘test_bitmask_2’, index: 0, depth: 1)
+ . ╰─ parent: (1): stack region
+ . ╰─ parent: (0): root region
+ */
+
+DEBUG_FUNCTION void
+region::dump () const
+{
+ text_art::dump (*this);
+}
+
/* Return a new json::string describing the region. */
json::value *
return false;
}
+/* Use DWI to create a text_art::widget describing this region in
+ a tree-like form, using PREFIX as a prefix (e.g. for field names). */
+
+std::unique_ptr<text_art::widget>
+region::make_dump_widget (const text_art::dump_widget_info &dwi,
+ const char *prefix) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = true;
+
+ if (prefix)
+ pp_printf (&pp, "%s: ", prefix);
+
+ pp_printf (&pp, "(%i): ", get_id ());
+ if (get_type ())
+ pp_printf (&pp, "%qT: ", get_type ());
+
+ print_dump_widget_label (&pp);
+
+ std::unique_ptr<text_art::tree_widget> w
+ (text_art::tree_widget::make (dwi, &pp));
+
+ add_dump_widget_children (*w, dwi);
+
+ if (m_parent)
+ w->add_child (m_parent->make_dump_widget (dwi, "parent"));
+
+ return w;
+}
+
+void
+region::add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* By default, add nothing (parent is added in make_dump_widget). */
+}
+
/* Generate a description of this region. */
DEBUG_FUNCTION label_text
function_name (&m_fun), m_index, get_stack_depth ());
}
+void
+frame_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "frame_region(%qs, index: %i, depth: %i)",
+ function_name (&m_fun), m_index, get_stack_depth ());
+}
+
const decl_region *
frame_region::get_region_for_local (region_model_manager *mgr,
tree expr,
pp_string (pp, "globals");
}
+void
+globals_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "globals");
+}
+
/* class code_region : public map_region. */
/* Implementation of region::dump_to_pp vfunc for code_region. */
pp_string (pp, "code_region()");
}
+void
+code_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "code region");
+}
+
/* class function_region : public region. */
/* Implementation of region::dump_to_pp vfunc for function_region. */
}
}
+void
+function_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "function_region(");
+ dump_quoted_tree (pp, m_fndecl);
+ pp_string (pp, ")");
+}
+
/* class label_region : public region. */
/* Implementation of region::dump_to_pp vfunc for label_region. */
}
}
+void
+label_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "label_region(");
+ dump_quoted_tree (pp, m_label);
+ pp_string (pp, ")");
+}
+
/* class stack_region : public region. */
/* Implementation of region::dump_to_pp vfunc for stack_region. */
pp_string (pp, "stack_region()");
}
+void
+stack_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "stack region");
+}
+
/* class heap_region : public region. */
/* Implementation of region::dump_to_pp vfunc for heap_region. */
pp_string (pp, "heap_region()");
}
+void
+heap_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "heap_region");
+}
+
/* class root_region : public region. */
/* root_region's ctor. */
pp_string (pp, "root_region()");
}
+void
+root_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "root region");
+}
+
/* class thread_local_region : public space_region. */
void
pp_string (pp, "thread_local_region()");
}
+void
+thread_local_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "thread_local_region");
+}
+
/* class symbolic_region : public map_region. */
/* symbolic_region's ctor. */
}
}
+void
+symbolic_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "symbolic_region: %<*%>");
+}
+
+void
+symbolic_region::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_sval_ptr->make_dump_widget (dwi, "m_sval_ptr"));
+}
+
/* class decl_region : public region. */
/* Implementation of region::dump_to_pp vfunc for decl_region. */
}
}
+void
+decl_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "decl_region(%qE)", m_decl);
+}
+
/* Get the stack depth for the frame containing this decl, or 0
for a global. */
}
}
+void
+field_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "field_region(%qE)", m_field);
+}
+
/* Implementation of region::get_relative_concrete_offset vfunc
for field_region. */
}
}
+void
+element_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "element_region: %<[]%>");
+}
+
+void
+element_region::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_index->make_dump_widget (dwi, "m_index"));
+}
+
/* Implementation of region::get_relative_concrete_offset vfunc
for element_region. */
}
}
+void
+offset_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "offset_region");
+}
+
+void
+offset_region::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_byte_offset->make_dump_widget (dwi, "m_byte_offset"));
+}
+
const svalue *
offset_region::get_bit_offset (region_model_manager *mgr) const
{
}
}
+void
+sized_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "sized_region");
+}
+
+void
+sized_region::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_byte_size_sval->make_dump_widget (dwi, "m_byte_size_sval"));
+}
+
/* Implementation of region::get_byte_size vfunc for sized_region. */
bool
}
}
+void
+cast_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "cast_region");
+}
+
+void
+cast_region::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child
+ (m_original_region->make_dump_widget (dwi, "m_original_region"));
+}
+
/* Implementation of region::get_relative_concrete_offset vfunc
for cast_region. */
pp_printf (pp, "heap_allocated_region(%i)", get_id ());
}
+void
+heap_allocated_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "heap_allocated_region");
+}
+
/* class alloca_region : public region. */
/* Implementation of region::dump_to_pp vfunc for alloca_region. */
pp_printf (pp, "alloca_region(%i)", get_id ());
}
+void
+alloca_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "alloca_region");
+}
+
/* class string_region : public region. */
/* Implementation of region::dump_to_pp vfunc for string_region. */
}
}
+void
+string_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_string (pp, "string_region(");
+ dump_tree (pp, m_string_cst);
+ pp_string (pp, ")");
+}
+
/* class bit_range_region : public region. */
/* Implementation of region::dump_to_pp vfunc for bit_range_region. */
}
}
+void
+bit_range_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "bit_range_region(m_bits: ");
+ m_bits.dump_to_pp (pp);
+ pp_string (pp, ")");
+}
+
/* Implementation of region::get_byte_size vfunc for bit_range_region. */
bool
}
}
+void
+var_arg_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "var_arg_region(arg_idx: %i)", m_idx);
+}
+
/* Get the frame_region for this var_arg_region. */
const frame_region *
pp_string (pp, "errno_region()");
}
+void
+errno_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "errno_region");
+}
+
/* class private_region : public region. */
void
pp_printf (pp, "private_region(%qs)", m_desc);
}
+void
+private_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "private_region(%qs)", m_desc);
+}
+
/* class unknown_region : public region. */
/* Implementation of region::dump_to_pp vfunc for unknown_region. */
pp_string (pp, "UNKNOWN_REGION");
}
+void
+unknown_region::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "unknown_region");
+}
+
} // namespace ana
#endif /* #if ENABLE_ANALYZER */
#define GCC_ANALYZER_REGION_H
#include "analyzer/symbol.h"
+#include "text-art/widget.h"
namespace ana {
virtual void dump_to_pp (pretty_printer *pp, bool simple) const = 0;
void dump (bool simple) const;
+ void dump () const;
json::value *to_json () const;
+
bool maybe_print_for_user (pretty_printer *pp,
const region_model &model) const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ const char *prefix = nullptr) const;
+
bool non_null_p () const;
static int cmp_ptr_ptr (const void *, const void *);
region_offset calc_offset (region_model_manager *mgr) const;
const svalue *calc_initial_value_at_main (region_model_manager *mgr) const;
+ virtual void
+ print_dump_widget_label (pretty_printer *pp) const = 0;
+ virtual void
+ add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &dwi) const;
+
const region *m_parent;
tree m_type;
void accept (visitor *v) const final override;
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
+
/* Accessors. */
const frame_region *get_calling_frame () const { return m_calling_frame; }
const function &get_function () const { return m_fun; }
/* region vfuncs. */
enum region_kind get_kind () const final override { return RK_GLOBALS; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
/* region vfuncs. */
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
enum region_kind get_kind () const final override { return RK_CODE; }
};
/* region vfuncs. */
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
+
enum region_kind get_kind () const final override { return RK_FUNCTION; }
const function_region *
dyn_cast_function_region () const final override{ return this; }
/* region vfuncs. */
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
enum region_kind get_kind () const final override { return RK_LABEL; }
tree get_label () const { return m_label; }
{}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
enum region_kind get_kind () const final override { return RK_STACK; }
};
enum region_kind get_kind () const final override { return RK_HEAP; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
enum region_kind get_kind () const final override { return RK_THREAD_LOCAL; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
enum region_kind get_kind () const final override { return RK_ROOT; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
enum region_kind get_kind () const final override { return RK_SYMBOLIC; }
void accept (visitor *v) const final override;
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi)
+ const final override;
const svalue *get_pointer () const { return m_sval_ptr; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+
bool tracked_p () const final override { return m_tracked; }
tree get_decl () const { return m_decl; }
enum region_kind get_kind () const final override { return RK_FIELD; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
+
const field_region *
dyn_cast_field_region () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &dwi)
+ const final override;
+
const svalue *get_index () const { return m_index; }
virtual bool
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &dwi)
+ const final override;
+
const svalue *get_byte_offset () const { return m_byte_offset; }
const svalue *get_bit_offset (region_model_manager *mgr) const;
void accept (visitor *v) const final override;
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &dwi)
+ const final override;
bool get_byte_size (byte_size_t *out) const final override;
bool get_bit_size (bit_size_t *out) const final override;
dyn_cast_cast_region () const final override { return this; }
void accept (visitor *v) const final override;
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &dwi)
+ const final override;
bool get_relative_concrete_offset (bit_offset_t *out) const final override;
get_kind () const final override { return RK_HEAP_ALLOCATED; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
/* An untyped region dynamically allocated on the stack via "alloca". */
enum region_kind get_kind () const final override { return RK_ALLOCA; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
/* A region for a STRING_CST. */
enum region_kind get_kind () const final override { return RK_STRING; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
/* We assume string literals are immutable, so we don't track them in
the store. */
enum region_kind get_kind () const final override { return RK_BIT_RANGE; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
const bit_range &get_bits () const { return m_bits; }
enum region_kind get_kind () const final override { return RK_VAR_ARG; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
const frame_region *get_frame_region () const;
unsigned get_index () const { return m_idx; }
enum region_kind get_kind () const final override { return RK_ERRNO; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
enum region_kind get_kind () const final override { return RK_PRIVATE; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
private:
const char *m_desc;
enum region_kind get_kind () const final override { return RK_UNKNOWN; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+ void print_dump_widget_label (pretty_printer *pp) const final override;
};
} // namespace ana
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
#include "stor-layout.h"
+#include "text-art/tree-widget.h"
#if ENABLE_ANALYZER
return map_obj;
}
+/* Add a child to PARENT_WIDGET expressing a binding between
+ KEY and SVAL. */
+
+static void
+add_binding_to_tree_widget (text_art::tree_widget &parent_widget,
+ const text_art::dump_widget_info &dwi,
+ const binding_key *key,
+ const svalue *sval)
+{
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_show_color (pp) = true;
+ const bool simple = true;
+
+ key->dump_to_pp (pp, simple);
+ pp_string (pp, ": ");
+ if (tree t = sval->get_type ())
+ dump_quoted_tree (pp, t);
+ pp_string (pp, " {");
+ sval->dump_to_pp (pp, simple);
+ pp_string (pp, "}");
+
+ parent_widget.add_child (text_art::tree_widget::make (dwi, pp));
+}
+
+void
+binding_map::add_to_tree_widget (text_art::tree_widget &parent_widget,
+ const text_art::dump_widget_info &dwi) const
+{
+ auto_vec <const binding_key *> binding_keys;
+ for (map_t::iterator iter = m_map.begin ();
+ iter != m_map.end (); ++iter)
+ {
+ const binding_key *key = (*iter).first;
+ binding_keys.safe_push (key);
+ }
+ binding_keys.qsort (binding_key::cmp_ptrs);
+
+ const binding_key *key;
+ unsigned i;
+ FOR_EACH_VEC_ELT (binding_keys, i, key)
+ {
+ const svalue *sval = *const_cast <map_t &> (m_map).get (key);
+ add_binding_to_tree_widget (parent_widget, dwi,
+ key, sval);
+ }
+}
+
+
/* Comparator for imposing an order on binding_maps. */
int
return cluster_obj;
}
+std::unique_ptr<text_art::widget>
+binding_cluster::make_dump_widget (const text_art::dump_widget_info &dwi,
+ store_manager *mgr) const
+{
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_show_color (pp) = true;
+ const bool simple = true;
+
+ m_base_region->dump_to_pp (pp, simple);
+ pp_string (pp, ": ");
+
+ if (const svalue *sval = maybe_get_simple_value (mgr))
+ {
+ /* Special-case to simplify dumps for the common case where
+ we just have one value directly bound to the whole of a
+ region. */
+ sval->dump_to_pp (pp, simple);
+ if (escaped_p ())
+ pp_string (pp, " (ESCAPED)");
+ if (touched_p ())
+ pp_string (pp, " (TOUCHED)");
+
+ return text_art::tree_widget::make (dwi, pp);
+ }
+ else
+ {
+ if (escaped_p ())
+ pp_string (pp, " (ESCAPED)");
+ if (touched_p ())
+ pp_string (pp, " (TOUCHED)");
+
+ std::unique_ptr<text_art::tree_widget> cluster_widget
+ (text_art::tree_widget::make (dwi, pp));
+
+ m_map.add_to_tree_widget (*cluster_widget, dwi);
+
+ return cluster_widget;
+ }
+}
+
/* Add a binding of SVAL of kind KIND to REG, unpacking SVAL if it is a
compound_sval. */
return store_obj;
}
+std::unique_ptr<text_art::widget>
+store::make_dump_widget (const text_art::dump_widget_info &dwi,
+ store_manager *mgr) const
+{
+ std::unique_ptr<text_art::tree_widget> store_widget
+ (text_art::tree_widget::make (dwi, "Store"));
+
+ store_widget->add_child
+ (text_art::tree_widget::from_fmt (dwi, nullptr,
+ "m_called_unknown_fn: %s",
+ m_called_unknown_fn ? "true" : "false"));
+
+ /* Sort into some deterministic order. */
+ auto_vec<const region *> base_regions;
+ for (cluster_map_t::iterator iter = m_cluster_map.begin ();
+ iter != m_cluster_map.end (); ++iter)
+ {
+ const region *base_reg = (*iter).first;
+ base_regions.safe_push (base_reg);
+ }
+ base_regions.qsort (region::cmp_ptr_ptr);
+
+ /* Gather clusters, organize by parent region, so that we can group
+ together locals, globals, etc. */
+ auto_vec<const region *> parent_regions;
+ get_sorted_parent_regions (&parent_regions, base_regions);
+
+ const region *parent_reg;
+ unsigned i;
+ FOR_EACH_VEC_ELT (parent_regions, i, parent_reg)
+ {
+ gcc_assert (parent_reg);
+
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_show_color (pp) = true;
+ const bool simple = true;
+
+ parent_reg->dump_to_pp (pp, simple);
+
+ std::unique_ptr<text_art::tree_widget> parent_reg_widget
+ (text_art::tree_widget::make (dwi, pp));
+
+ const region *base_reg;
+ unsigned j;
+ FOR_EACH_VEC_ELT (base_regions, j, base_reg)
+ {
+ /* This is O(N * M), but N ought to be small. */
+ if (base_reg->get_parent_region () != parent_reg)
+ continue;
+ binding_cluster *cluster
+ = *const_cast<cluster_map_t &> (m_cluster_map).get (base_reg);
+ parent_reg_widget->add_child
+ (cluster->make_dump_widget (dwi, mgr));
+ }
+ store_widget->add_child (std::move (parent_reg_widget));
+ }
+
+ return store_widget;
+}
+
/* Get any svalue bound to REG, or NULL. */
const svalue *
#ifndef GCC_ANALYZER_STORE_H
#define GCC_ANALYZER_STORE_H
+#include "text-art/tree-widget.h"
+
/* Implementation of the region-based ternary model described in:
"A Memory Model for Static Analysis of C Programs"
(Zhongxing Xu, Ted Kremenek, and Jian Zhang)
json::object *to_json () const;
+ void add_to_tree_widget (text_art::tree_widget &parent_widget,
+ const text_art::dump_widget_info &dwi) const;
+
bool apply_ctor_to_region (const region *parent_reg, tree ctor,
region_model_manager *mgr);
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ store_manager *mgr) const;
+
void bind (store_manager *mgr, const region *, const svalue *);
void clobber_region (store_manager *mgr, const region *reg);
json::object *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi,
+ store_manager *mgr) const;
+
const svalue *get_any_binding (store_manager *mgr, const region *reg) const;
bool called_unknown_fn_p () const { return m_called_unknown_fn; }
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "analyzer/region-model.h"
#include "diagnostic.h"
#include "tree-diagnostic.h"
+#include "make-unique.h"
+#include "text-art/dump.h"
#if ENABLE_ANALYZER
/* class svalue. */
+/* Dump a tree-like representation of this svalue and its constituent symbols
+ to stderr, using global_dc's colorization and theming options.
+
+ For example:
+ . (gdb) call index_sval->dump()
+ . (27): ‘int’: initial_svalue
+ . ╰─ m_reg: (26): ‘int’: decl_region(‘x_10(D)’)
+ . ╰─ parent: (9): frame_region(‘test_bitmask_2’, index: 0, depth: 1)
+ . ╰─ parent: (1): stack region
+ . ╰─ parent: (0): root region
+ */
+
+DEBUG_FUNCTION void
+svalue::dump () const
+{
+ text_art::dump (*this);
+}
+
/* Dump a representation of this svalue to stderr. */
DEBUG_FUNCTION void
return false;
}
+/* Use DWI to create a text_art::widget describing this svalue in
+ a tree-like form, using PREFIX as a prefix (e.g. for field names).
+ We do this via two vfuncs:
+ (a) print_dump_widget_label, to populate the text of a tree_widget, and
+ (b) add_dump_widget_children, to add children to the tree_widget. */
+
+std::unique_ptr<text_art::widget>
+svalue::make_dump_widget (const text_art::dump_widget_info &dwi,
+ const char *prefix) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = true;
+
+ if (prefix)
+ pp_printf (&pp, "%s: ", prefix);
+
+ pp_printf (&pp, "(%i): ", get_id ());
+ if (get_type ())
+ pp_printf (&pp, "%qT: ", get_type ());
+
+ print_dump_widget_label (&pp);
+
+ std::unique_ptr<text_art::tree_widget> w
+ (text_art::tree_widget::make (dwi, &pp));
+
+ add_dump_widget_children (*w, dwi);
+
+ return w;
+}
+
/* If this svalue is a constant_svalue, return the underlying tree constant.
Otherwise return NULL_TREE. */
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ region_svalue. */
+
+void
+region_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "region_svalue: %qs", "&");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ region_svalue. */
+
+void
+region_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_reg->make_dump_widget (dwi));
+}
+
/* Implementation of svalue::accept vfunc for region_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ constant_svalue. */
+
+void
+constant_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "constant_svalue (%qE)", m_cst_expr);
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ constant_svalue. */
+
+void
+constant_svalue::
+add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* No children. */
+}
+
/* Implementation of svalue::accept vfunc for constant_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ unknown_svalue. */
+
+void
+unknown_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "unknown_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ unknown_svalue. */
+
+void
+unknown_svalue::
+add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* No children. */
+}
+
/* Implementation of svalue::accept vfunc for unknown_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ poisoned_svalue. */
+
+void
+poisoned_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "poisoned_svalue(%s)", poison_kind_to_str (m_kind));
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ poisoned_svalue. */
+
+void
+poisoned_svalue::
+add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* No children. */
+}
+
/* Implementation of svalue::accept vfunc for poisoned_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ initial_svalue. */
+
+void
+initial_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "initial_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ initial_svalue. */
+
+void
+initial_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_reg->make_dump_widget (dwi, "m_reg"));
+}
+
/* Implementation of svalue::accept vfunc for initial_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ unaryop_svalue. */
+
+void
+unaryop_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp,
+ "unaryop_svalue(%s)",
+ get_tree_code_name (m_op));
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ unaryop_svalue. */
+
+void
+unaryop_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_arg->make_dump_widget (dwi));
+}
+
/* Implementation of svalue::accept vfunc for unaryop_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ binop_svalue. */
+
+void
+binop_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp,
+ "binop_svalue(%s: %qs)",
+ get_tree_code_name (m_op),
+ op_symbol_code (m_op));
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ binop_svalue. */
+
+void
+binop_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_arg0->make_dump_widget (dwi));
+ w.add_child (m_arg1->make_dump_widget (dwi));
+}
+
/* Implementation of svalue::accept vfunc for binop_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ sub_svalue. */
+
+void
+sub_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "sub_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ sub_svalue. */
+
+void
+sub_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_parent_svalue->make_dump_widget (dwi, "m_parent_svalue"));
+ w.add_child (m_subregion->make_dump_widget (dwi, "m_subregion"));
+}
+
/* Implementation of svalue::accept vfunc for sub_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ repeated_svalue. */
+
+void
+repeated_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "repeated_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ repeated_svalue. */
+
+void
+repeated_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_outer_size->make_dump_widget (dwi, "m_outer_size"));
+ w.add_child (m_inner_svalue->make_dump_widget (dwi, "m_inner_svalue"));
+}
+
/* Implementation of svalue::accept vfunc for repeated_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ bits_within_svalue. */
+
+void
+bits_within_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "bits_within_svalue: ");
+ m_bits.dump_to_pp (pp);
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ bits_within_svalue. */
+
+void
+bits_within_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_inner_svalue->make_dump_widget (dwi, "m_inner_svalue"));
+}
+
/* Implementation of svalue::maybe_fold_bits_within vfunc
for bits_within_svalue. */
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ widening_svalue. */
+
+void
+widening_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "widening_svalue at ");
+ m_point.print (pp, format (false));
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ widening_svalue. */
+
+void
+widening_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_base_sval->make_dump_widget (dwi, "m_base_sval"));
+ w.add_child (m_iter_sval->make_dump_widget (dwi, "m_iter_sval"));
+}
+
/* Implementation of svalue::accept vfunc for widening_svalue. */
void
pp_printf (pp, "placeholder_svalue (%qs)", m_name);
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ placeholder_svalue. */
+
+void
+placeholder_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "placeholder_svalue: %qs", m_name);
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ placeholder_svalue. */
+
+void
+placeholder_svalue::
+add_dump_widget_children (text_art::tree_widget &,
+ const text_art::dump_widget_info &) const
+{
+ /* No children. */
+}
+
/* Implementation of svalue::accept vfunc for placeholder_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ unmergeable_svalue. */
+
+void
+unmergeable_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "unmergeable_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ unmergeable_svalue. */
+
+void
+unmergeable_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_arg->make_dump_widget (dwi));
+}
+
/* Implementation of svalue::accept vfunc for unmergeable_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ compound_svalue. */
+
+void
+compound_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "compound_svalue");
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ compound_svalue. */
+
+void
+compound_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ m_map.add_to_tree_widget (w, dwi);
+}
+
/* Implementation of svalue::accept vfunc for compound_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ conjured_svalue. */
+
+void
+conjured_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "conjured_svalue (");
+ pp_gimple_stmt_1 (pp, m_stmt, 0, (dump_flags_t)0);
+ if (m_idx != 0)
+ pp_printf (pp, ", %i", m_idx);
+ pp_character (pp, ')');
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ conjured_svalue. */
+
+void
+conjured_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ w.add_child (m_id_reg->make_dump_widget (dwi));
+}
+
/* Implementation of svalue::accept vfunc for conjured_svalue. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ asm_output_svalue. */
+
+void
+asm_output_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "asm_output_svalue(%qs, %%%i)",
+ get_asm_string (),
+ get_output_idx ());
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ asm_output_svalue. */
+
+void
+asm_output_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ for (unsigned i = 0; i < m_num_inputs; i++)
+ {
+ pretty_printer pp;
+ pp_printf (&pp, "arg %i", i);
+ w.add_child (m_input_arr[i]->make_dump_widget (dwi,
+ pp_formatted_text (&pp)));
+ }
+}
+
/* Subroutine of asm_output_svalue::dump_to_pp. */
void
}
}
+/* Implementation of svalue::print_dump_widget_label vfunc for
+ const_fn_result_svalue. */
+
+void
+const_fn_result_svalue::print_dump_widget_label (pretty_printer *pp) const
+{
+ pp_printf (pp, "const_fn_result_svalue: %qD", m_fndecl);
+}
+
+/* Implementation of svalue::add_dump_widget_children vfunc for
+ const_fn_result_svalue. */
+
+void
+const_fn_result_svalue::
+add_dump_widget_children (text_art::tree_widget &w,
+ const text_art::dump_widget_info &dwi) const
+{
+ for (unsigned i = 0; i < m_num_inputs; i++)
+ {
+ pretty_printer pp;
+ pp_printf (&pp, "arg %i", i);
+ w.add_child (m_input_arr[i]->make_dump_widget (dwi,
+ pp_formatted_text (&pp)));
+ }
+}
+
/* Subroutine of const_fn_result_svalue::dump_to_pp. */
void
#include "analyzer/symbol.h"
#include "analyzer/store.h"
#include "analyzer/program-point.h"
+#include "text-art/widget.h"
using namespace ana;
+using text_art::dump_widget_info;
namespace ana {
pretty_printer *pp) const;
virtual void dump_to_pp (pretty_printer *pp, bool simple) const = 0;
- void dump (bool simple=true) const;
+ void dump () const;
+ void dump (bool simple) const;
label_text get_desc (bool simple=true) const;
json::value *to_json () const;
+ std::unique_ptr<text_art::widget>
+ make_dump_widget (const dump_widget_info &dwi,
+ const char *prefix = nullptr) const;
+
virtual const region_svalue *
dyn_cast_region_svalue () const { return NULL; }
virtual const constant_svalue *
: symbol (c, id), m_type (type)
{}
+ void print_svalue_node_label (pretty_printer *pp) const;
+
private:
+ virtual void
+ print_dump_widget_label (pretty_printer *pp) const = 0;
+ virtual void
+ add_dump_widget_children (text_art::tree_widget &,
+ const dump_widget_info &dwi) const = 0;
+
tree m_type;
};
dyn_cast_region_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
dyn_cast_constant_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
enum svalue_kind get_kind () const final override { return SK_UNKNOWN; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const svalue *
dyn_cast_poisoned_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const svalue *
dyn_cast_setjmp_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
int get_enode_index () const;
dyn_cast_initial_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
dyn_cast_unaryop_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const svalue *get_outer_size () const { return m_outer_size; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
dyn_cast_unmergeable_svalue () const final override { return this; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
bool implicitly_live_p (const svalue_set *,
const region_model *) const final override;
enum svalue_kind get_kind () const final override { return SK_PLACEHOLDER; }
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const char *get_name () const { return m_name; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const function_point &get_point () const { return m_point; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const binding_map &get_map () const { return m_map; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const gimple *get_stmt () const { return m_stmt; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
const char *get_asm_string () const { return m_asm_string; }
}
void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+
+ void
+ print_dump_widget_label (pretty_printer *pp) const final override;
+ void
+ add_dump_widget_children (text_art::tree_widget &w,
+ const dump_widget_info &dwi) const final override;
+
void accept (visitor *v) const final override;
tree get_fndecl () const { return m_fndecl; }
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "tree.h"
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
#include "make-unique.h"
instances, to @code{svalue} instances. The bindings are organized into
clusters, where regions accessible via well-defined pointer arithmetic
are in the same cluster. The representation is graph-like because values
-can be pointers to regions. It also stores a constraint_manager,
+can be pointers to regions. It also stores a @code{constraint_manager},
capturing relationships between the values.
Because each node in the @code{exploded_graph} has a @code{region_model},
and each of the latter is graph-like, the @code{exploded_graph} is in some
ways a graph of graphs.
-Here's an example of printing a @code{program_state}, showing the
-@code{region_model} within it, along with state for the @code{malloc}
-state machine.
+There are several ``dump'' functions for use when debugging the analyzer.
+
+Consider this example C code:
+
+@smallexample
+void *
+calls_malloc (size_t n)
+@{
+ void *result = malloc (1024);
+ return result; /* HERE */
+@}
+
+void test (size_t n)
+@{
+ void *ptr = calls_malloc (n * 4);
+ /* etc. */
+@}
+@end smallexample
+
+and the state at the point @code{/* HERE */} for the interprocedural
+analysis case where @code{calls_malloc} returns back to @code{test}.
+
+Here's an example of printing a @code{program_state} at @code{/* HERE */},
+showing the @code{region_model} within it, along with state for the
+@code{malloc} state machine.
@smallexample
-(gdb) call debug (*this)
+(gdb) break region_model::on_return
+[..snip...]
+(gdb) run
+[..snip...]
+(gdb) up
+[..snip...]
+(gdb) call state->dump()
+State
+├─ Region Model
+│ ├─ Current Frame: frame: ‘calls_malloc’@@2
+│ ├─ Store
+│ │ ├─ m_called_unknown_fn: false
+│ │ ├─ frame: ‘test’@@1
+│ │ │ ╰─ _1: (INIT_VAL(n_2(D))*(size_t)4)
+│ │ ╰─ frame: ‘calls_malloc’@@2
+│ │ ├─ result_4: &HEAP_ALLOCATED_REGION(27)
+│ │ ╰─ _5: &HEAP_ALLOCATED_REGION(27)
+│ ╰─ Dynamic Extents
+│ ╰─ HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4)
+╰─ ‘malloc’ state machine
+ ╰─ 0x468cb40: &HEAP_ALLOCATED_REGION(27): unchecked (@{free@}) (‘result_4’)
+@end smallexample
+
+Within the store, there are bindings clusters for the SSA names for the
+various local variables within frames for @code{test} and
+@code{calls_malloc}. For example,
+
+@itemize @bullet
+@item
+within @code{test} the whole cluster for @code{_1} is bound
+to a @code{binop_svalue} representing @code{n * 4}, and
+@item
+within @code{test} the whole cluster for @code{result_4} is bound to a
+@code{region_svalue} pointing at @code{HEAP_ALLOCATED_REGION(12)}.
+@end itemize
+
+Additionally, this latter pointer has the @code{unchecked} state for the
+@code{malloc} state machine indicating it hasn't yet been checked against
+@code{NULL} since the allocation call.
+
+We also see that the state has captured the size of the heap-allocated
+region (``Dynamic Extents'').
+
+This visualization can also be seen within the output of
+@option{-fdump-analyzer-exploded-nodes-2} and
+@option{-fdump-analyzer-exploded-nodes-3}.
+
+As well as the above visualizations of states, there are tree-like
+visualizations for instances of @code{svalue} and @code{region}, showing
+their IDs and how they are constructed from simpler symbols:
+
+@smallexample
+(gdb) break region_model::set_dynamic_extents
+[..snip...]
+(gdb) run
+[..snip...]
+(gdb) up
+[..snip...]
+(gdb) call size_in_bytes->dump()
+(17): ‘long unsigned int’: binop_svalue(mult_expr: ‘*’)
+├─ (15): ‘size_t’: initial_svalue
+│ ╰─ m_reg: (12): ‘size_t’: decl_region(‘n_2(D)’)
+│ ╰─ parent: (9): frame_region(‘test’, index: 0, depth: 1)
+│ ╰─ parent: (1): stack region
+│ ╰─ parent: (0): root region
+╰─ (16): ‘size_t’: constant_svalue (‘4’)
+@end smallexample
+
+i.e. that @code{size_in_bytes} is a @code{binop_svalue} expressing
+the result of multiplying
+
+@itemize @bullet
+@item
+the initial value of the @code{PARM_DECL} @code{n_2(D)} for the
+parameter @code{n} within the frame for @code{test} by
+@item
+the constant value @code{4}.
+@end itemize
+
+The above visualizations rely on the @code{text_art::widget} framework,
+which performs significant work to lay out the output, so there is also
+an earlier, simpler, form of dumping available. For states there is:
+
+@smallexample
+(gdb) call state->dump(eg.m_ext_state, true)
rmodel:
-stack depth: 1
+stack depth: 2
+ frame (index 1): frame: ‘calls_malloc’@@2
frame (index 0): frame: ‘test’@@1
clusters within frame: ‘test’@@1
- cluster for: ptr_3: &HEAP_ALLOCATED_REGION(12)
+ cluster for: _1: (INIT_VAL(n_2(D))*(size_t)4)
+clusters within frame: ‘calls_malloc’@@2
+ cluster for: result_4: &HEAP_ALLOCATED_REGION(27)
+ cluster for: _5: &HEAP_ALLOCATED_REGION(27)
m_called_unknown_fn: FALSE
constraint_manager:
equiv classes:
constraints:
+dynamic_extents:
+ HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4)
malloc:
- 0x2e89590: &HEAP_ALLOCATED_REGION(12): unchecked ('ptr_3')
+ 0x468cb40: &HEAP_ALLOCATED_REGION(27): unchecked (@{free@}) (‘result_4’)
@end smallexample
-This is the state at the point of returning from @code{calls_malloc} back
-to @code{test} in the following:
+or for @code{region_model} just:
@smallexample
-void *
-calls_malloc (void)
-@{
- void *result = malloc (1024);
- return result;
-@}
-
-void test (void)
-@{
- void *ptr = calls_malloc ();
- /* etc. */
-@}
+(gdb) call state->m_region_model->debug()
+stack depth: 2
+ frame (index 1): frame: ‘calls_malloc’@@2
+ frame (index 0): frame: ‘test’@@1
+clusters within frame: ‘test’@@1
+ cluster for: _1: (INIT_VAL(n_2(D))*(size_t)4)
+clusters within frame: ‘calls_malloc’@@2
+ cluster for: result_4: &HEAP_ALLOCATED_REGION(27)
+ cluster for: _5: &HEAP_ALLOCATED_REGION(27)
+m_called_unknown_fn: FALSE
+constraint_manager:
+ equiv classes:
+ constraints:
+dynamic_extents:
+ HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4)
@end smallexample
-Within the store, there is the cluster for @code{ptr_3} within the frame
-for @code{test}, where the whole cluster is bound to a pointer value,
-pointing at @code{HEAP_ALLOCATED_REGION(12)}. Additionally, this pointer
-has the @code{unchecked} state for the @code{malloc} state machine
-indicating it hasn't yet been checked against NULL since the allocation
-call.
+and for instances of @code{svalue} and @code{region} there is this
+older dump implementation, which takes a @code{bool simple} flag
+controlling the verbosity of the dump:
+
+@smallexample
+(gdb) call size_in_bytes->dump(true)
+(INIT_VAL(n_2(D))*(size_t)4)
+
+(gdb) call size_in_bytes->dump(false)
+binop_svalue (mult_expr, initial_svalue(‘size_t’, decl_region(frame_region(‘test’, index: 0, depth: 1), ‘size_t’, ‘n_2(D)’)), constant_svalue(‘size_t’, 4))
+@end smallexample
@subsection Analyzer Paths
/* { dg-options "-g" } */
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
/* { dg-options "-g" } */
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
/* { dg-options "-g" } */
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
/* { dg-options "-g" } */
#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
--- /dev/null
+/* Support for creating dump widgets.
+ Copyright (C) 2024 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_TEXT_ART_DUMP_WIDGET_INFO_H
+#define GCC_TEXT_ART_DUMP_WIDGET_INFO_H
+
+namespace text_art {
+
+/* A bundle of state for use by make_dump_widget implementations.
+ The referenced objects are expected to outlive the widgets
+ themselves. */
+
+struct dump_widget_info
+{
+ dump_widget_info (text_art::style_manager &sm,
+ const text_art::theme &theme,
+ text_art::style::id_t tree_style_id)
+ : m_sm (sm),
+ m_theme (theme),
+ m_tree_style_id (tree_style_id)
+ {
+ }
+
+ text_art::style::id_t get_tree_style_id () const
+ {
+ return m_tree_style_id;
+ }
+
+ text_art::style_manager &m_sm;
+ const text_art::theme &m_theme;
+ text_art::style::id_t m_tree_style_id;
+};
+
+} // namespace text_art
+
+#endif /* GCC_TEXT_ART_DUMP_WIDGET_INFO_H */
--- /dev/null
+/* Templates for dumping objects.
+ Copyright (C) 2024 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_TEXT_ART_DUMP_H
+#define GCC_TEXT_ART_DUMP_H
+
+#include "tree-diagnostic.h"
+#include "text-art/canvas.h"
+#include "text-art/widget.h"
+#include "text-art/dump-widget-info.h"
+
+/* A family of templates for dumping objects via the text_art::widget
+ system.
+ Any type T that has a make_dump_widget member function ought to be
+ dumpable via these functions. */
+
+namespace text_art {
+
+/* Dump OBJ to PP, using OBJ's make_dump_widget member function. */
+
+template <typename T>
+void dump_to_pp (const T &obj, text_art::theme *theme, pretty_printer *pp)
+{
+ if (!theme)
+ return;
+
+ style_manager sm;
+ style tree_style (get_style_from_color_cap_name ("note"));
+
+ style::id_t tree_style_id (sm.get_or_create_id (tree_style));
+
+ dump_widget_info dwi (sm, *theme, tree_style_id);
+ if (std::unique_ptr<widget> w = obj.make_dump_widget (dwi))
+ {
+ text_art::canvas c (w->to_canvas (dwi.m_sm));
+ c.print_to_pp (pp);
+ }
+}
+
+/* Dump OBJ to OUTF, using OBJ's make_dump_widget member function. */
+
+template <typename T>
+void dump_to_file (const T &obj, FILE *outf)
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ if (outf == stderr)
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ pp.buffer->stream = outf;
+
+ text_art::theme *theme = global_dc->get_diagram_theme ();
+ dump_to_pp (obj, theme, &pp);
+ pp_flush (&pp);
+}
+
+/* Dump OBJ to stderr, using OBJ's make_dump_widget member function. */
+
+template <typename T>
+void dump (const T &obj)
+{
+ dump_to_file (obj, stderr);
+}
+
+} // namespace text_art
+
+#endif /* GCC_TEXT_ART_DUMP_H */
text_art_ruler_cc_tests ();
text_art_table_cc_tests ();
text_art_widget_cc_tests ();
+ text_art_tree_widget_cc_tests ();
}
/* Implementation detail of ASSERT_CANVAS_STREQ. */
extern void text_art_style_cc_tests ();
extern void text_art_styled_string_cc_tests ();
extern void text_art_table_cc_tests ();
+extern void text_art_tree_widget_cc_tests ();
extern void text_art_widget_cc_tests ();
extern void text_art_tests ();
return '+';
case cell_kind::CFG_FROM_DOWN_TO_RIGHT:
return '+';
+
+ case cell_kind::TREE_CHILD_NON_FINAL:
+ return '+';
+ case cell_kind::TREE_CHILD_FINAL:
+ return '`';
+ case cell_kind::TREE_X_CONNECTOR:
+ return '-';
+ case cell_kind::TREE_Y_CONNECTOR:
+ return '|';
}
}
return 0x250c; /* "┌" U+250C: BOX DRAWINGS LIGHT DOWN AND RIGHT */
case cell_kind::CFG_FROM_DOWN_TO_RIGHT:
return 0x2514; /* "└": U+2514: BOX DRAWINGS LIGHT UP AND RIGHT */
+
+ case cell_kind::TREE_CHILD_NON_FINAL:
+ return 0x251C; /* "├": U+251C: BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+ case cell_kind::TREE_CHILD_FINAL:
+ return 0x2570; /* "╰": U+2570 BOX DRAWINGS LIGHT ARC UP AND RIGHT. */
+ case cell_kind::TREE_X_CONNECTOR:
+ return 0x2500; /* "─": U+2500: BOX DRAWINGS LIGHT HORIZONTAL */
+ case cell_kind::TREE_Y_CONNECTOR:
+ return 0x2502; /* "│": U+2502: BOX DRAWINGS LIGHT VERTICAL */
}
}
CFG_FROM_DOWN_TO_LEFT, /* e.g. "+". */
CFG_LEFT, /* e.g. "-". */
CFG_FROM_LEFT_TO_DOWN, /* e.g. "+". */
- CFG_FROM_DOWN_TO_RIGHT /* e.g. "+". */
+ CFG_FROM_DOWN_TO_RIGHT, /* e.g. "+". */
+
+ /* Tree stuff. */
+ TREE_CHILD_NON_FINAL, /* e.g. "├" or "+". */
+ TREE_CHILD_FINAL, /* e.g. "╰" or "`". */
+ TREE_X_CONNECTOR, /* e.g. "─" or "-". */
+ TREE_Y_CONNECTOR /* e.g. "|" or "|". */
};
virtual ~theme () = default;
--- /dev/null
+/* Tree diagrams.
+ Copyright (C) 2024 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/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "pretty-print.h"
+#include "selftest.h"
+#include "make-unique.h"
+#include "text-art/selftests.h"
+#include "text-art/tree-widget.h"
+#include "text-art/dump-widget-info.h"
+
+using namespace text_art;
+
+/* class text_art::tree_widget : public text_art::widget. */
+
+static const int margin_width = 3;
+
+std::unique_ptr<tree_widget>
+tree_widget::make (styled_string str, const theme &theme, style::id_t style_id)
+{
+ return ::make_unique <tree_widget>
+ (::make_unique <text_widget> (std::move (str)),
+ theme,
+ style_id);
+}
+
+std::unique_ptr<tree_widget>
+tree_widget::make (const dump_widget_info &dwi, pretty_printer *pp)
+{
+ return tree_widget::make (styled_string (dwi.m_sm, pp_formatted_text (pp)),
+ dwi.m_theme,
+ dwi.get_tree_style_id ());
+}
+
+std::unique_ptr<tree_widget>
+tree_widget::make (const dump_widget_info &dwi, const char *str)
+{
+ return tree_widget::make (styled_string (dwi.m_sm, str),
+ dwi.m_theme,
+ dwi.get_tree_style_id ());
+}
+
+std::unique_ptr<tree_widget>
+tree_widget::from_fmt (const dump_widget_info &dwi,
+ printer_fn format_decoder,
+ const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ styled_string styled_str
+ (styled_string::from_fmt_va (dwi.m_sm, format_decoder, fmt, &ap));
+ va_end (ap);
+ return make (std::move (styled_str), dwi.m_theme, dwi.get_tree_style_id ());
+}
+
+const char *
+tree_widget::get_desc () const
+{
+ return "tree_widget";
+}
+
+canvas::size_t
+tree_widget::calc_req_size ()
+{
+ canvas::size_t result (0, 0);
+ if (m_node)
+ {
+ canvas::size_t node_req_size = m_node->get_req_size ();
+ result.h += node_req_size.h;
+ result.w = std::max (result.w, node_req_size.w);
+ }
+ for (auto &child : m_children)
+ {
+ canvas::size_t child_req_size = child->get_req_size ();
+ result.h += child_req_size.h;
+ result.w = std::max (result.w, child_req_size.w + margin_width);
+ }
+ return result;
+}
+
+void
+tree_widget::update_child_alloc_rects ()
+{
+ const int x = get_min_x ();
+ int y = get_min_y ();
+ if (m_node)
+ {
+ m_node->set_alloc_rect
+ (canvas::rect_t (canvas::coord_t (x, y),
+ canvas::size_t (get_alloc_w (),
+ m_node->get_req_h ())));
+ y += m_node->get_req_h ();
+ }
+ for (auto &child : m_children)
+ {
+ child->set_alloc_rect
+ (canvas::rect_t (canvas::coord_t (x + margin_width, y),
+ canvas::size_t (get_alloc_w () - margin_width,
+ child->get_req_h ())));
+ y += child->get_req_h ();
+ }
+}
+
+void
+tree_widget::paint_to_canvas (canvas &canvas)
+{
+ if (m_node)
+ m_node->paint_to_canvas (canvas);
+ const int min_x = get_min_x ();
+ const canvas::cell_t cell_child_non_final
+ (m_theme.get_cell (theme::cell_kind::TREE_CHILD_NON_FINAL, m_style_id));
+ const canvas::cell_t cell_child_final
+ (m_theme.get_cell (theme::cell_kind::TREE_CHILD_FINAL, m_style_id));
+ const canvas::cell_t cell_x_connector
+ (m_theme.get_cell (theme::cell_kind::TREE_X_CONNECTOR, m_style_id));
+ const canvas::cell_t cell_y_connector
+ (m_theme.get_cell (theme::cell_kind::TREE_Y_CONNECTOR, m_style_id));
+ size_t idx = 0;
+ for (auto &child : m_children)
+ {
+ child->paint_to_canvas (canvas);
+
+ const bool last_child = (++idx == m_children.size ());
+ canvas.paint (canvas::coord_t (min_x + 1, child->get_min_y ()),
+ cell_x_connector);
+ canvas.paint (canvas::coord_t (min_x, child->get_min_y ()),
+ last_child ? cell_child_final : cell_child_non_final);
+ if (!last_child)
+ for (int y = child->get_min_y () + 1; y <= child ->get_max_y (); y++)
+ canvas.paint (canvas::coord_t (min_x, y), cell_y_connector);
+ }
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+static std::unique_ptr<tree_widget>
+make_test_tree_widget (const dump_widget_info &dwi)
+{
+ std::unique_ptr<tree_widget> w
+ (tree_widget::from_fmt (dwi, nullptr, "Root"));
+ for (int i = 0; i < 3; i++)
+ {
+ std::unique_ptr<tree_widget> c
+ (tree_widget::from_fmt (dwi, nullptr, "Child %i", i));
+ for (int j = 0; j < 3; j++)
+ c->add_child (tree_widget::from_fmt (dwi, nullptr,
+ "Grandchild %i %i", i, j));
+ w->add_child (std::move (c));
+ }
+ return w;
+}
+
+static void
+test_tree_widget ()
+{
+ style_manager sm;
+
+ style::id_t default_style_id (sm.get_or_create_id (style ()));
+
+ {
+ ascii_theme theme;
+ dump_widget_info dwi (sm, theme, default_style_id);
+ canvas c (make_test_tree_widget (dwi)->to_canvas (sm));
+ ASSERT_CANVAS_STREQ
+ (c, false,
+ ("Root\n"
+ "+- Child 0\n"
+ "| +- Grandchild 0 0\n"
+ "| +- Grandchild 0 1\n"
+ "| `- Grandchild 0 2\n"
+ "+- Child 1\n"
+ "| +- Grandchild 1 0\n"
+ "| +- Grandchild 1 1\n"
+ "| `- Grandchild 1 2\n"
+ "`- Child 2\n"
+ " +- Grandchild 2 0\n"
+ " +- Grandchild 2 1\n"
+ " `- Grandchild 2 2\n"));
+ }
+
+ {
+ unicode_theme theme;
+ dump_widget_info dwi (sm, theme, default_style_id);
+ canvas c (make_test_tree_widget (dwi)->to_canvas (sm));
+ ASSERT_CANVAS_STREQ
+ (c, false,
+ ("Root\n"
+ "├─ Child 0\n"
+ "│ ├─ Grandchild 0 0\n"
+ "│ ├─ Grandchild 0 1\n"
+ "│ ╰─ Grandchild 0 2\n"
+ "├─ Child 1\n"
+ "│ ├─ Grandchild 1 0\n"
+ "│ ├─ Grandchild 1 1\n"
+ "│ ╰─ Grandchild 1 2\n"
+ "╰─ Child 2\n"
+ " ├─ Grandchild 2 0\n"
+ " ├─ Grandchild 2 1\n"
+ " ╰─ Grandchild 2 2\n"));
+ }
+}
+
+/* Run all selftests in this file. */
+
+void
+text_art_tree_widget_cc_tests ()
+{
+ test_tree_widget ();
+}
+
+} // namespace selftest
+
+
+#endif /* #if CHECKING_P */
--- /dev/null
+/* Tree diagrams.
+ Copyright (C) 2024 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_TEXT_ART_TREE_WIDGET_H
+#define GCC_TEXT_ART_TREE_WIDGET_H
+
+#include "text-art/canvas.h"
+#include "text-art/widget.h"
+
+namespace text_art {
+
+class dump_widget_info;
+
+class tree_widget : public widget
+{
+public:
+ tree_widget (std::unique_ptr<widget> node,
+ const theme &theme,
+ style::id_t style_id)
+ : m_node (std::move (node)),
+ m_theme (theme),
+ m_style_id (style_id)
+ {
+ }
+
+ static std::unique_ptr<tree_widget>
+ make (styled_string str, const theme &theme, style::id_t style_id);
+
+ static std::unique_ptr<tree_widget>
+ make (const dump_widget_info &dwi, pretty_printer *pp);
+
+ static std::unique_ptr<tree_widget>
+ make (const dump_widget_info &dwi, const char *str);
+
+ static std::unique_ptr<tree_widget>
+ from_fmt (const dump_widget_info &dwi,
+ printer_fn format_decoder,
+ const char *fmt, ...)
+ ATTRIBUTE_GCC_PPDIAG(3, 4);
+
+ const char *get_desc () const override;
+ canvas::size_t calc_req_size () final override;
+ void update_child_alloc_rects () final override;
+ void paint_to_canvas (canvas &canvas) final override;
+
+ void add_child (std::unique_ptr<widget> child)
+ {
+ if (child)
+ m_children.push_back (std::move (child));
+ }
+
+ size_t get_num_children () const
+ {
+ return m_children.size ();
+ }
+
+private:
+ std::unique_ptr<widget> m_node;
+ std::vector<std::unique_ptr<widget>> m_children;
+ const theme &m_theme;
+ style::id_t m_style_id;
+};
+
+} // namespace text_art
+
+#endif /* GCC_TEXT_ART_TREE_WIDGET_H */