Add new text_art::tree_widget and use it in analyzer
This patch adds a new text_art::tree_widget, which makes it easy to generate hierarchical visualizations using either ASCII: +- Child 0 | +- Grandchild 0 0 | +- Grandchild 0 1 | `- Grandchild 0 2 +- Child 1 | +- Grandchild 1 0 | +- Grandchild 1 1 | `- Grandchild 1 2 `- Child 2 +- Grandchild 2 0 +- Grandchild 2 1 `- Grandchild 2 2 or Unicode: Root ├─ Child 0 │ ├─ Grandchild 0 0 │ ├─ Grandchild 0 1 │ ╰─ Grandchild 0 2 ├─ Child 1 │ ├─ Grandchild 1 0 │ ├─ Grandchild 1 1 │ ╰─ Grandchild 1 2 ╰─ Child 2 ├─ Grandchild 2 0 ├─ Grandchild 2 1 ╰─ Grandchild 2 2 potentially with colorization of the connecting lines. It adds a new template for typename T: void text_art::dump<T> (const T&); for using this to dump any object to stderr that supports a make_dump_widget method, with similar templates for dumping to a pretty_printer * and a FILE *. It uses this within the analyzer to add two new families of dumping methods: one for program states, e.g.: (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’) and the other for showing the detail of the recursive makeup of svalues and regions, e.g. the (INIT_VAL(n_2(D))*(size_t)4) from above: (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’) I've already found both of these useful when debugging analyzer issues. The patch uses the former to update the output of -fdump-analyzer-exploded-nodes-2 and -fdump-analyzer-exploded-nodes-3. The older dumping functions within the analyzer are retained in case they turn out to still be useful for debugging. gcc/ChangeLog: * Makefile.in (OBJS-libcommon): Add text-art/tree-widget.o. * doc/analyzer.texi: Rewrite discussion of dumping state to cover the text_art::tree_widget-based dumps, with a more interesting example. * text-art/dump-widget-info.h: New file. * text-art/dump.h: New file. * text-art/selftests.cc (selftest::text_art_tests): Call text_art_tree_widget_cc_tests. * text-art/selftests.h (selftest::text_art_tree_widget_cc_tests): New decl. * text-art/theme.cc (ascii_theme::get_cppchar): Handle the various cell_kind::TREE_*. (unicode_theme::get_cppchar): Likewise. * text-art/theme.h (enum class theme::cell_kind): Add TREE_CHILD_NON_FINAL, TREE_CHILD_FINAL, TREE_X_CONNECTOR, and TREE_Y_CONNECTOR. * text-art/tree-widget.cc: New file. gcc/analyzer/ChangeLog: * call-details.cc: Define INCLUDE_VECTOR. * call-info.cc: Likewise. * call-summary.cc: Likewise. * checker-event.cc: Likewise. * checker-path.cc: Likewise. * complexity.cc: Likewise. * constraint-manager.cc: Likewise. (bounded_range::make_dump_widget): New. (bounded_ranges::add_to_dump_widget): New. (equiv_class::make_dump_widget): New. (constraint::make_dump_widget): New. (bounded_ranges_constraint::make_dump_widget): New. (constraint_manager::make_dump_widget): New. * constraint-manager.h (bounded_range::make_dump_widget): New decl. (bounded_ranges::add_to_dump_widget): New decl. (equiv_class::make_dump_widget): New decl. (constraint::make_dump_widget): New decl. (bounded_ranges_constraint::make_dump_widget): New decl. (constraint_manager::make_dump_widget): New decl. * diagnostic-manager.cc: Define INCLUDE_VECTOR. * engine.cc: Likewise. Include "text-art/dump.h". (setjmp_svalue::print_dump_widget_label): New. (setjmp_svalue::add_dump_widget_children): New. (exploded_graph::dump_exploded_nodes): Use text_art::dump_to_file for -fdump-analyzer-exploded-nodes-2 and -fdump-analyzer-exploded-nodes-3. Fix overlong line. * feasible-graph.cc: Define INCLUDE_VECTOR. * infinite-recursion.cc: Likewise. * kf-analyzer.cc: Likewise. * kf-lang-cp.cc: Likewise. * kf.cc: Likewise. * known-function-manager.cc: Likewise. * pending-diagnostic.cc: Likewise. * program-point.cc: Likewise. * program-state.cc: Likewise. Include "text-art/tree-widget" and "text-art/dump.h". (sm_state_map::make_dump_widget): New. (program_state::dump): New. (program_state::make_dump_widget): New. * program-state.h: Include "text-art/widget.h". (sm_state_map::make_dump_widget): New decl. (program_state::dump): New decl. (program_state::make_dump_widget): New decl. * ranges.cc: Define INCLUDE_VECTOR. * record-layout.cc: Likewise. * region-model-asm.cc: Likewise. * region-model-manager.cc: Likewise. * region-model-reachability.cc: Likewise. * region-model.cc: Likewise. Include "text-art/tree-widget.h". (region_to_value_map::make_dump_widget): New. (region_model::dump): New. (region_model::make_dump_widget): New. (selftest::test_dump): Add test of dump_to_pp<region_model>. * region-model.h: Include "text-art/widget.h" and "text-art/dump.h". (region_to_value_map::make_dump_widget): New decl. (region_model::dump): New decl. (region_model::make_dump_widget): New decl. * region.cc: Define INCLUDE_VECTOR and include "text-art/dump.h". (region::dump): New. (region::make_dump_widget): New. (region::add_dump_widget_children): New. (frame_region::print_dump_widget_label): New. (globals_region::print_dump_widget_label): New. (code_region::print_dump_widget_label): New. (function_region::print_dump_widget_label): New. (label_region::print_dump_widget_label): New. (stack_region::print_dump_widget_label): New. (heap_region::print_dump_widget_label): New. (root_region::print_dump_widget_label): New. (thread_local_region::print_dump_widget_label): New. (symbolic_region::print_dump_widget_label): New. (symbolic_region::add_dump_widget_children): New. (decl_region::print_dump_widget_label): New. (field_region::print_dump_widget_label): New. (element_region::print_dump_widget_label): New. (element_region::add_dump_widget_children): New. (offset_region::print_dump_widget_label): New. (offset_region::add_dump_widget_children): New. (sized_region::print_dump_widget_label): New. (sized_region::add_dump_widget_children): New. (cast_region::print_dump_widget_label): New. (cast_region::add_dump_widget_children): New. (heap_allocated_region::print_dump_widget_label): New. (alloca_region::print_dump_widget_label): New. (string_region::print_dump_widget_label): New. (bit_range_region::print_dump_widget_label): New. (var_arg_region::print_dump_widget_label): New. (errno_region::print_dump_widget_label): New. (private_region::print_dump_widget_label): New. (unknown_region::print_dump_widget_label): New. * region.h: Include "text-art/widget.h". (region::dump): New decl. (region::make_dump_widget): New decl. (region::add_dump_widget_children): New decl. (frame_region::print_dump_widget_label): New decl. (globals_region::print_dump_widget_label): New decl. (code_region::print_dump_widget_label): New decl. (function_region::print_dump_widget_label): New decl. (label_region::print_dump_widget_label): New decl. (stack_region::print_dump_widget_label): New decl. (heap_region::print_dump_widget_label): New decl. (root_region::print_dump_widget_label): New decl. (thread_local_region::print_dump_widget_label): New decl. (symbolic_region::print_dump_widget_label): New decl. (symbolic_region::add_dump_widget_children): New decl. (decl_region::print_dump_widget_label): New decl. (field_region::print_dump_widget_label): New decl. (element_region::print_dump_widget_label): New decl. (element_region::add_dump_widget_children): New decl. (offset_region::print_dump_widget_label): New decl. (offset_region::add_dump_widget_children): New decl. (sized_region::print_dump_widget_label): New decl. (sized_region::add_dump_widget_children): New decl. (cast_region::print_dump_widget_label): New decl. (cast_region::add_dump_widget_children): New decl. (heap_allocated_region::print_dump_widget_label): New decl. (alloca_region::print_dump_widget_label): New decl. (string_region::print_dump_widget_label): New decl. (bit_range_region::print_dump_widget_label): New decl. (var_arg_region::print_dump_widget_label): New decl. (errno_region::print_dump_widget_label): New decl. (private_region::print_dump_widget_label): New decl. (unknown_region::print_dump_widget_label): New decl. * sm-fd.cc: Define INCLUDE_VECTOR. * sm-file.cc: Likewise. * sm-malloc.cc: Likewise. * sm-pattern-test.cc: Likewise. * sm-signal.cc: Likewise. * sm-taint.cc: Likewise. * sm.cc: Likewise. * state-purge.cc: Likewise. * store.cc: Likewise. Include "text-art/tree-widget.h". (add_binding_to_tree_widget): New. (binding_map::add_to_tree_widget): New. (binding_cluster::make_dump_widget): New. (store::make_dump_widget): New. * store.h: Include "text-art/tree-widget.h". (binding_map::add_to_tree_widget): New decl. (binding_cluster::make_dump_widget): New decl. (store::make_dump_widget): New decl. * svalue.cc: Define INCLUDE_VECTOR. Include "make-unique.h" and "text-art/dump.h". (svalue::dump): New. (svalue::make_dump_widget): New. (region_svalue::print_dump_widget_label): New. (region_svalue::add_dump_widget_children): New. (constant_svalue::print_dump_widget_label): New. (constant_svalue::add_dump_widget_children): New. (unknown_svalue::print_dump_widget_label): New. (unknown_svalue::add_dump_widget_children): New. (poisoned_svalue::print_dump_widget_label): New. (poisoned_svalue::add_dump_widget_children): New. (initial_svalue::print_dump_widget_label): New. (initial_svalue::add_dump_widget_children): New. (unaryop_svalue::print_dump_widget_label): New. (unaryop_svalue::add_dump_widget_children): New. (binop_svalue::print_dump_widget_label): New. (binop_svalue::add_dump_widget_children): New. (sub_svalue::print_dump_widget_label): New. (sub_svalue::add_dump_widget_children): New. (repeated_svalue::print_dump_widget_label): New. (repeated_svalue::add_dump_widget_children): New. (bits_within_svalue::print_dump_widget_label): New. (bits_within_svalue::add_dump_widget_children): New. (widening_svalue::print_dump_widget_label): New. (widening_svalue::add_dump_widget_children): New. (placeholder_svalue::print_dump_widget_label): New. (placeholder_svalue::add_dump_widget_children): New. (unmergeable_svalue::print_dump_widget_label): New. (unmergeable_svalue::add_dump_widget_children): New. (compound_svalue::print_dump_widget_label): New. (compound_svalue::add_dump_widget_children): New. (conjured_svalue::print_dump_widget_label): New. (conjured_svalue::add_dump_widget_children): New. (asm_output_svalue::print_dump_widget_label): New. (asm_output_svalue::add_dump_widget_children): New. (const_fn_result_svalue::print_dump_widget_label): New. (const_fn_result_svalue::add_dump_widget_children): New. * svalue.h: Include "text-art/widget.h". Add "using text_art::dump_widget_info". (svalue::dump): New decl. (svalue::make_dump_widget): New decl. (svalue::print_dump_widget_label): New decl. (svalue::print_dump_widget_label): New decl. (svalue::add_dump_widget_children): New decl. (region_svalue::print_dump_widget_label): New decl. (region_svalue::add_dump_widget_children): New decl. (constant_svalue::print_dump_widget_label): New decl. (constant_svalue::add_dump_widget_children): New decl. (unknown_svalue::print_dump_widget_label): New decl. (unknown_svalue::add_dump_widget_children): New decl. (poisoned_svalue::print_dump_widget_label): New decl. (poisoned_svalue::add_dump_widget_children): New decl. (initial_svalue::print_dump_widget_label): New decl. (initial_svalue::add_dump_widget_children): New decl. (unaryop_svalue::print_dump_widget_label): New decl. (unaryop_svalue::add_dump_widget_children): New decl. (binop_svalue::print_dump_widget_label): New decl. (binop_svalue::add_dump_widget_children): New decl. (sub_svalue::print_dump_widget_label): New decl. (sub_svalue::add_dump_widget_children): New decl. (repeated_svalue::print_dump_widget_label): New decl. (repeated_svalue::add_dump_widget_children): New decl. (bits_within_svalue::print_dump_widget_label): New decl. (bits_within_svalue::add_dump_widget_children): New decl. (widening_svalue::print_dump_widget_label): New decl. (widening_svalue::add_dump_widget_children): New decl. (placeholder_svalue::print_dump_widget_label): New decl. (placeholder_svalue::add_dump_widget_children): New decl. (unmergeable_svalue::print_dump_widget_label): New decl. (unmergeable_svalue::add_dump_widget_children): New decl. (compound_svalue::print_dump_widget_label): New decl. (compound_svalue::add_dump_widget_children): New decl. (conjured_svalue::print_dump_widget_label): New decl. (conjured_svalue::add_dump_widget_children): New decl. (asm_output_svalue::print_dump_widget_label): New decl. (asm_output_svalue::add_dump_widget_children): New decl. (const_fn_result_svalue::print_dump_widget_label): New decl. (const_fn_result_svalue::add_dump_widget_children): New decl. * trimmed-graph.cc: Define INCLUDE_VECTOR. * varargs.cc: Likewise. gcc/testsuite/ChangeLog: * gcc.dg/plugin/analyzer_cpython_plugin.c: Define INCLUDE_VECTOR. * gcc.dg/plugin/analyzer_gil_plugin.c: Likewise. * gcc.dg/plugin/analyzer_kernel_plugin.c: Likewise. * gcc.dg/plugin/analyzer_known_fns_plugin.c: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
370df6ef0f
commit
97238e4217
57 changed files with 2074 additions and 36 deletions
|
@ -1836,6 +1836,7 @@ OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
|
|||
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
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
@ -462,6 +463,14 @@ bounded_range::to_json () const
|
|||
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
|
||||
|
@ -729,6 +738,14 @@ bounded_ranges::to_json () const
|
|||
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. */
|
||||
|
||||
|
@ -1129,6 +1146,39 @@ equiv_class::to_json () const
|
|||
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. */
|
||||
|
@ -1354,6 +1404,17 @@ constraint::to_json () const
|
|||
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
|
||||
|
@ -1430,6 +1491,18 @@ bounded_ranges_constraint::to_json () const
|
|||
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
|
||||
|
@ -1756,6 +1829,33 @@ constraint_manager::to_json () 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. */
|
||||
|
|
|
@ -87,6 +87,9 @@ struct bounded_range
|
|||
|
||||
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,
|
||||
|
@ -134,6 +137,9 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -267,6 +273,10 @@ public:
|
|||
|
||||
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
|
||||
|
@ -343,6 +353,10 @@ class constraint
|
|||
|
||||
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;
|
||||
|
||||
|
@ -394,6 +408,9 @@ public:
|
|||
|
||||
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;
|
||||
};
|
||||
|
@ -427,6 +444,9 @@ public:
|
|||
|
||||
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];
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
@ -68,6 +69,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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. */
|
||||
|
||||
|
@ -263,6 +265,26 @@ setjmp_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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
|
||||
|
@ -5420,7 +5442,7 @@ exploded_graph::dump_exploded_nodes () const
|
|||
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);
|
||||
|
@ -5439,7 +5461,8 @@ exploded_graph::dump_exploded_nodes () const
|
|||
= 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);
|
||||
|
@ -5447,7 +5470,7 @@ exploded_graph::dump_exploded_nodes () const
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
@ -53,6 +54,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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
|
||||
|
||||
|
@ -303,6 +306,85 @@ sm_state_map::to_json () const
|
|||
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). */
|
||||
|
||||
|
@ -1101,6 +1183,14 @@ program_state::dump (const extrinsic_state &ext_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,
|
||||
|
@ -1138,6 +1228,28 @@ program_state::to_json (const extrinsic_state &ext_state) const
|
|||
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. */
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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. */
|
||||
|
@ -117,6 +119,10 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -223,9 +229,13 @@ public:
|
|||
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;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_ALGORITHM
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
@ -80,6 +81,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/feasible-graph.h"
|
||||
#include "analyzer/record-layout.h"
|
||||
#include "diagnostic-format-sarif.h"
|
||||
#include "text-art/tree-widget.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -256,6 +258,39 @@ region_to_value_map::to_json () const
|
|||
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.
|
||||
|
||||
|
@ -465,6 +500,14 @@ region_model::dump (bool simple) const
|
|||
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
|
||||
|
@ -489,6 +532,33 @@ region_model::to_json () const
|
|||
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
|
||||
|
@ -7307,6 +7377,14 @@ test_dump ()
|
|||
"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,
|
||||
|
|
|
@ -35,6 +35,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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;
|
||||
|
||||
|
@ -177,6 +179,9 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
|
@ -277,11 +282,15 @@ class region_model
|
|||
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 ();
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
@ -57,6 +58,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/region-model.h"
|
||||
#include "analyzer/sm.h"
|
||||
#include "analyzer/program-state.h"
|
||||
#include "text-art/dump.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -1040,6 +1042,23 @@ region::dump (bool simple) const
|
|||
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 *
|
||||
|
@ -1072,6 +1091,44 @@ region::maybe_print_for_user (pretty_printer *pp,
|
|||
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
|
||||
|
@ -1341,6 +1398,13 @@ frame_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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,
|
||||
|
@ -1411,6 +1475,12 @@ globals_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -1424,6 +1494,12 @@ code_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -1443,6 +1519,14 @@ function_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -1462,6 +1546,14 @@ label_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -1475,6 +1567,12 @@ stack_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -1488,6 +1586,12 @@ heap_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -1508,6 +1612,12 @@ root_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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
|
||||
|
@ -1519,6 +1629,12 @@ thread_local_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -1568,6 +1684,20 @@ symbolic_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -1587,6 +1717,12 @@ decl_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
|
@ -1816,6 +1952,12 @@ field_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
|
@ -1892,6 +2034,20 @@ element_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
|
@ -1980,6 +2136,20 @@ offset_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -2053,6 +2223,20 @@ sized_region::dump_to_pp (pretty_printer *pp, bool simple) 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
|
||||
|
@ -2124,6 +2308,21 @@ cast_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
|
@ -2147,6 +2346,12 @@ heap_allocated_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -2160,6 +2365,12 @@ alloca_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -2182,6 +2393,14 @@ string_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
@ -2207,6 +2426,14 @@ bit_range_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -2293,6 +2520,12 @@ var_arg_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
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 *
|
||||
|
@ -2313,6 +2546,12 @@ errno_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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
|
||||
|
@ -2324,6 +2563,12 @@ private_region::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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. */
|
||||
|
@ -2334,6 +2579,12 @@ unknown_region::dump_to_pp (pretty_printer *pp, bool /*simple*/) const
|
|||
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 */
|
||||
|
|
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#define GCC_ANALYZER_REGION_H
|
||||
|
||||
#include "analyzer/symbol.h"
|
||||
#include "text-art/widget.h"
|
||||
|
||||
namespace ana {
|
||||
|
||||
|
@ -173,12 +174,18 @@ public:
|
|||
|
||||
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 *);
|
||||
|
@ -257,6 +264,12 @@ public:
|
|||
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;
|
||||
|
||||
|
@ -357,6 +370,8 @@ public:
|
|||
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; }
|
||||
|
@ -416,6 +431,7 @@ class globals_region : public space_region
|
|||
/* 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
|
||||
|
@ -442,6 +458,7 @@ public:
|
|||
|
||||
/* 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; }
|
||||
};
|
||||
|
||||
|
@ -472,6 +489,8 @@ public:
|
|||
|
||||
/* 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; }
|
||||
|
@ -508,6 +527,7 @@ public:
|
|||
|
||||
/* 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; }
|
||||
|
@ -539,6 +559,7 @@ public:
|
|||
{}
|
||||
|
||||
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; }
|
||||
};
|
||||
|
@ -567,6 +588,7 @@ public:
|
|||
|
||||
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
|
||||
|
@ -593,6 +615,7 @@ public:
|
|||
|
||||
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
|
||||
|
@ -618,6 +641,7 @@ public:
|
|||
|
||||
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
|
||||
|
@ -680,6 +704,11 @@ public:
|
|||
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; }
|
||||
|
||||
|
@ -724,6 +753,9 @@ public:
|
|||
|
||||
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; }
|
||||
|
@ -808,6 +840,8 @@ public:
|
|||
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; }
|
||||
|
||||
|
@ -896,6 +930,13 @@ public:
|
|||
|
||||
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
|
||||
|
@ -983,6 +1024,13 @@ public:
|
|||
|
||||
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;
|
||||
|
||||
|
@ -1073,6 +1121,12 @@ public:
|
|||
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;
|
||||
|
@ -1162,6 +1216,12 @@ public:
|
|||
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;
|
||||
|
||||
|
@ -1203,6 +1263,7 @@ public:
|
|||
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". */
|
||||
|
@ -1217,6 +1278,7 @@ public:
|
|||
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. */
|
||||
|
@ -1235,6 +1297,7 @@ public:
|
|||
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. */
|
||||
|
@ -1314,6 +1377,7 @@ public:
|
|||
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; }
|
||||
|
||||
|
@ -1402,6 +1466,7 @@ public:
|
|||
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; }
|
||||
|
@ -1440,6 +1505,7 @@ public:
|
|||
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
|
||||
|
@ -1473,6 +1539,7 @@ public:
|
|||
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;
|
||||
|
@ -1502,6 +1569,7 @@ public:
|
|||
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
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
@ -54,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/call-summary.h"
|
||||
#include "analyzer/analyzer-selftests.h"
|
||||
#include "stor-layout.h"
|
||||
#include "text-art/tree-widget.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -810,6 +812,56 @@ binding_map::to_json () const
|
|||
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
|
||||
|
@ -1399,6 +1451,48 @@ binding_cluster::to_json () const
|
|||
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. */
|
||||
|
||||
|
@ -2613,6 +2707,68 @@ store::to_json () const
|
|||
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 *
|
||||
|
|
|
@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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)
|
||||
|
@ -546,6 +548,9 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
|
@ -612,6 +617,10 @@ public:
|
|||
|
||||
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);
|
||||
|
@ -750,6 +759,10 @@ public:
|
|||
|
||||
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; }
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
@ -49,6 +50,8 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "analyzer/region-model.h"
|
||||
#include "diagnostic.h"
|
||||
#include "tree-diagnostic.h"
|
||||
#include "make-unique.h"
|
||||
#include "text-art/dump.h"
|
||||
|
||||
#if ENABLE_ANALYZER
|
||||
|
||||
|
@ -60,6 +63,24 @@ static int cmp_csts_and_types (const_tree cst1, const_tree cst2);
|
|||
|
||||
/* 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
|
||||
|
@ -203,6 +224,37 @@ svalue::maybe_print_for_user (pretty_printer *pp,
|
|||
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. */
|
||||
|
||||
|
@ -842,6 +894,26 @@ region_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -942,6 +1014,26 @@ constant_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1085,6 +1177,26 @@ unknown_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1146,6 +1258,26 @@ poisoned_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1195,6 +1327,26 @@ initial_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1287,6 +1439,28 @@ unaryop_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1389,6 +1563,30 @@ binop_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1449,6 +1647,27 @@ sub_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1519,6 +1738,27 @@ repeated_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1644,6 +1884,27 @@ bits_within_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
|
@ -1712,6 +1973,28 @@ widening_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1850,6 +2133,26 @@ placeholder_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
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
|
||||
|
@ -1879,6 +2182,26 @@ unmergeable_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -1950,6 +2273,26 @@ compound_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -2081,6 +2424,30 @@ conjured_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -2136,6 +2503,34 @@ asm_output_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
@ -2198,6 +2593,32 @@ const_fn_result_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
|||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -24,8 +24,10 @@ along with GCC; see the file COPYING3. If not see
|
|||
#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 {
|
||||
|
||||
|
@ -99,11 +101,16 @@ public:
|
|||
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 *
|
||||
|
@ -186,7 +193,15 @@ public:
|
|||
: 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;
|
||||
};
|
||||
|
||||
|
@ -237,6 +252,13 @@ public:
|
|||
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;
|
||||
|
@ -319,6 +341,13 @@ public:
|
|||
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;
|
||||
|
@ -372,6 +401,13 @@ public:
|
|||
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 *
|
||||
|
@ -445,6 +481,13 @@ public:
|
|||
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 *
|
||||
|
@ -555,6 +598,13 @@ public:
|
|||
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;
|
||||
|
@ -605,6 +655,13 @@ public:
|
|||
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;
|
||||
|
@ -680,6 +737,13 @@ public:
|
|||
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;
|
||||
|
@ -777,6 +841,13 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -858,6 +929,13 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -941,6 +1019,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
@ -1030,6 +1115,13 @@ public:
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -1089,6 +1181,13 @@ public:
|
|||
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;
|
||||
|
@ -1127,6 +1226,13 @@ public:
|
|||
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; }
|
||||
|
@ -1223,6 +1329,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
@ -1318,6 +1431,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
@ -1455,6 +1575,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
@ -1580,6 +1707,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
@ -1713,6 +1847,13 @@ public:
|
|||
}
|
||||
|
||||
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; }
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
|
|
|
@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "make-unique.h"
|
||||
|
|
|
@ -259,56 +259,175 @@ memory, with a @code{store} recording a binding between @code{region}
|
|||
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.
|
||||
|
||||
@smallexample
|
||||
(gdb) call debug (*this)
|
||||
rmodel:
|
||||
stack depth: 1
|
||||
frame (index 0): frame: ‘test’@@1
|
||||
clusters within frame: ‘test’@@1
|
||||
cluster for: ptr_3: &HEAP_ALLOCATED_REGION(12)
|
||||
m_called_unknown_fn: FALSE
|
||||
constraint_manager:
|
||||
equiv classes:
|
||||
constraints:
|
||||
malloc:
|
||||
0x2e89590: &HEAP_ALLOCATED_REGION(12): unchecked ('ptr_3')
|
||||
@end smallexample
|
||||
|
||||
This is the state at the point of returning from @code{calls_malloc} back
|
||||
to @code{test} in the following:
|
||||
Consider this example C code:
|
||||
|
||||
@smallexample
|
||||
void *
|
||||
calls_malloc (void)
|
||||
calls_malloc (size_t n)
|
||||
@{
|
||||
void *result = malloc (1024);
|
||||
return result;
|
||||
return result; /* HERE */
|
||||
@}
|
||||
|
||||
void test (void)
|
||||
void test (size_t n)
|
||||
@{
|
||||
void *ptr = calls_malloc ();
|
||||
void *ptr = calls_malloc (n * 4);
|
||||
/* etc. */
|
||||
@}
|
||||
@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 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) 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: 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)
|
||||
malloc:
|
||||
0x468cb40: &HEAP_ALLOCATED_REGION(27): unchecked (@{free@}) (‘result_4’)
|
||||
@end smallexample
|
||||
|
||||
or for @code{region_model} just:
|
||||
|
||||
@smallexample
|
||||
(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
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* { dg-options "-g" } */
|
||||
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "gcc-plugin.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
/* { dg-options "-g" } */
|
||||
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "gcc-plugin.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* { dg-options "-g" } */
|
||||
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "gcc-plugin.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/* { dg-options "-g" } */
|
||||
|
||||
#define INCLUDE_MEMORY
|
||||
#define INCLUDE_VECTOR
|
||||
#include "gcc-plugin.h"
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
|
|
53
gcc/text-art/dump-widget-info.h
Normal file
53
gcc/text-art/dump-widget-info.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* 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 */
|
83
gcc/text-art/dump.h
Normal file
83
gcc/text-art/dump.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* 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 */
|
|
@ -42,6 +42,7 @@ selftest::text_art_tests ()
|
|||
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. */
|
||||
|
|
|
@ -34,6 +34,7 @@ extern void text_art_ruler_cc_tests ();
|
|||
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 ();
|
||||
|
|
|
@ -155,6 +155,15 @@ ascii_theme::get_cppchar (enum cell_kind kind) const
|
|||
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 '|';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -240,5 +249,14 @@ unicode_theme::get_cppchar (enum cell_kind kind) const
|
|||
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 */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,13 @@ class theme
|
|||
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;
|
||||
|
|
237
gcc/text-art/tree-widget.cc
Normal file
237
gcc/text-art/tree-widget.cc
Normal file
|
@ -0,0 +1,237 @@
|
|||
/* 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 */
|
83
gcc/text-art/tree-widget.h
Normal file
83
gcc/text-art/tree-widget.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* 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 */
|
Loading…
Add table
Reference in a new issue