/* Regions of memory. Copyright (C) 2019-2020 Free Software Foundation, Inc. Contributed by David Malcolm . 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 . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "diagnostic-core.h" #include "gimple-pretty-print.h" #include "function.h" #include "basic-block.h" #include "gimple.h" #include "gimple-iterator.h" #include "diagnostic-core.h" #include "graphviz.h" #include "options.h" #include "cgraph.h" #include "tree-dfa.h" #include "stringpool.h" #include "convert.h" #include "target.h" #include "fold-const.h" #include "tree-pretty-print.h" #include "diagnostic-color.h" #include "diagnostic-metadata.h" #include "tristate.h" #include "bitmap.h" #include "selftest.h" #include "function.h" #include "json.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "ordered-hash-map.h" #include "options.h" #include "cgraph.h" #include "cfg.h" #include "digraph.h" #include "analyzer/supergraph.h" #include "sbitmap.h" #include "analyzer/call-string.h" #include "analyzer/program-point.h" #include "analyzer/store.h" #include "analyzer/region.h" #include "analyzer/region-model.h" #if ENABLE_ANALYZER namespace ana { /* class region and its various subclasses. */ /* class region. */ region::~region () { delete m_cached_offset; } /* Compare REG1 and REG2 by id. */ int region::cmp_ids (const region *reg1, const region *reg2) { return (long)reg1->get_id () - (long)reg2->get_id (); } /* Determine the base region for this region: when considering bindings for this region, the base region is the ancestor which identifies which cluster they should be partitioned into. Regions within the same struct/union/array are in the same cluster. Different decls are in different clusters. */ const region * region::get_base_region () const { const region *iter = this; while (iter) { switch (iter->get_kind ()) { case RK_FIELD: case RK_ELEMENT: case RK_OFFSET: iter = iter->get_parent_region (); continue; case RK_CAST: iter = iter->dyn_cast_cast_region ()->get_original_region (); continue; default: return iter; } } return iter; } /* Return true if get_base_region() == this for this region. */ bool region::base_region_p () const { switch (get_kind ()) { /* Region kinds representing a descendent of a base region. */ case RK_FIELD: case RK_ELEMENT: case RK_OFFSET: case RK_CAST: return false; default: return true; } } /* Return true if this region is ELDER or one of its descendents. */ bool region::descendent_of_p (const region *elder) const { const region *iter = this; while (iter) { if (iter == elder) return true; if (iter->get_kind () == RK_CAST) iter = iter->dyn_cast_cast_region ()->get_original_region (); else iter = iter->get_parent_region (); } return false; } /* If this region is a frame_region, or a descendent of one, return it. Otherwise return NULL. */ const frame_region * region::maybe_get_frame_region () const { const region *iter = this; while (iter) { if (const frame_region *frame_reg = iter->dyn_cast_frame_region ()) return frame_reg; if (iter->get_kind () == RK_CAST) iter = iter->dyn_cast_cast_region ()->get_original_region (); else iter = iter->get_parent_region (); } return NULL; } /* If this region is a decl_region, return the decl. Otherwise return NULL. */ tree region::maybe_get_decl () const { if (const decl_region *decl_reg = dyn_cast_decl_region ()) return decl_reg->get_decl (); return NULL_TREE; } /* Get the region_offset for this region (calculating it on the first call and caching it internally). */ region_offset region::get_offset () const { if(!m_cached_offset) m_cached_offset = new region_offset (calc_offset ()); return *m_cached_offset; } /* If the size of this region (in bytes) is known statically, write it to *OUT and return true. Otherwise return false. */ bool region::get_byte_size (byte_size_t *out) const { tree type = get_type (); /* Bail out e.g. for heap-allocated regions. */ if (!type) return false; HOST_WIDE_INT bytes = int_size_in_bytes (type); if (bytes == -1) return false; *out = bytes; return true; } /* If the size of this region (in bits) is known statically, write it to *OUT and return true. Otherwise return false. */ bool region::get_bit_size (bit_size_t *out) const { byte_size_t byte_size; if (!get_byte_size (&byte_size)) return false; *out = byte_size * BITS_PER_UNIT; return true; } /* Get the field within RECORD_TYPE at BIT_OFFSET. */ static tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset) { gcc_assert (TREE_CODE (record_type) == RECORD_TYPE); if (bit_offset < 0) return NULL; /* Find the first field that has an offset > BIT_OFFSET, then return the one preceding it. Skip other trees within the chain, such as FUNCTION_DECLs. */ tree last_field = NULL_TREE; for (tree iter = TYPE_FIELDS (record_type); iter != NULL_TREE; iter = DECL_CHAIN (iter)) { if (TREE_CODE (iter) == FIELD_DECL) { int iter_field_offset = int_bit_position (iter); if (bit_offset < iter_field_offset) return last_field; last_field = iter; } } return last_field; } /* Populate *OUT with descendent regions of type TYPE that match RELATIVE_BIT_OFFSET and SIZE_IN_BITS within this region. */ void region::get_subregions_for_binding (region_model_manager *mgr, bit_offset_t relative_bit_offset, bit_size_t size_in_bits, tree type, auto_vec *out) const { if (get_type () == NULL_TREE || type == NULL_TREE) return; if (relative_bit_offset == 0 && types_compatible_p (get_type (), type)) { out->safe_push (this); return; } switch (TREE_CODE (get_type ())) { case ARRAY_TYPE: { tree element_type = TREE_TYPE (get_type ()); HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (element_type); if (hwi_byte_size > 0) { HOST_WIDE_INT bits_per_element = hwi_byte_size << LOG2_BITS_PER_UNIT; HOST_WIDE_INT element_index = (relative_bit_offset.to_shwi () / bits_per_element); tree element_index_cst = build_int_cst (integer_type_node, element_index); HOST_WIDE_INT inner_bit_offset = relative_bit_offset.to_shwi () % bits_per_element; const region *subregion = mgr->get_element_region (this, element_type, mgr->get_or_create_constant_svalue (element_index_cst)); subregion->get_subregions_for_binding (mgr, inner_bit_offset, size_in_bits, type, out); } } break; case RECORD_TYPE: { /* The bit offset might be *within* one of the fields (such as with nested structs). So we want to find the enclosing field, adjust the offset, and repeat. */ if (tree field = get_field_at_bit_offset (get_type (), relative_bit_offset)) { int field_bit_offset = int_bit_position (field); const region *subregion = mgr->get_field_region (this, field); subregion->get_subregions_for_binding (mgr, relative_bit_offset - field_bit_offset, size_in_bits, type, out); } } break; case UNION_TYPE: { for (tree field = TYPE_FIELDS (get_type ()); field != NULL_TREE; field = DECL_CHAIN (field)) { if (TREE_CODE (field) != FIELD_DECL) continue; const region *subregion = mgr->get_field_region (this, field); subregion->get_subregions_for_binding (mgr, relative_bit_offset, size_in_bits, type, out); } } break; default: /* Do nothing. */ break; } } /* Walk from this region up to the base region within its cluster, calculating the offset relative to the base region, either as an offset in bits, or a symbolic offset. */ region_offset region::calc_offset () const { const region *iter_region = this; bit_offset_t accum_bit_offset = 0; while (iter_region) { switch (iter_region->get_kind ()) { case RK_FIELD: { const field_region *field_reg = (const field_region *)iter_region; iter_region = iter_region->get_parent_region (); /* Compare with e.g. gimple-fold.c's fold_nonarray_ctor_reference. */ tree field = field_reg->get_field (); tree byte_offset = DECL_FIELD_OFFSET (field); if (TREE_CODE (byte_offset) != INTEGER_CST) return region_offset::make_symbolic (iter_region); tree field_offset = DECL_FIELD_BIT_OFFSET (field); /* Compute bit offset of the field. */ offset_int bitoffset = (wi::to_offset (field_offset) + (wi::to_offset (byte_offset) << LOG2_BITS_PER_UNIT)); accum_bit_offset += bitoffset; } continue; case RK_ELEMENT: { const element_region *element_reg = (const element_region *)iter_region; iter_region = iter_region->get_parent_region (); if (tree idx_cst = element_reg->get_index ()->maybe_get_constant ()) { gcc_assert (TREE_CODE (idx_cst) == INTEGER_CST); tree elem_type = element_reg->get_type (); offset_int element_idx = wi::to_offset (idx_cst); /* First, use int_size_in_bytes, to reject the case where we have an incomplete type, or a non-constant value. */ HOST_WIDE_INT hwi_byte_size = int_size_in_bytes (elem_type); if (hwi_byte_size > 0) { offset_int element_bit_size = hwi_byte_size << LOG2_BITS_PER_UNIT; offset_int element_bit_offset = element_idx * element_bit_size; accum_bit_offset += element_bit_offset; continue; } } return region_offset::make_symbolic (iter_region); } continue; case RK_OFFSET: { const offset_region *offset_reg = (const offset_region *)iter_region; iter_region = iter_region->get_parent_region (); if (tree byte_offset_cst = offset_reg->get_byte_offset ()->maybe_get_constant ()) { gcc_assert (TREE_CODE (byte_offset_cst) == INTEGER_CST); /* Use a signed value for the byte offset, to handle negative offsets. */ HOST_WIDE_INT byte_offset = wi::to_offset (byte_offset_cst).to_shwi (); HOST_WIDE_INT bit_offset = byte_offset * BITS_PER_UNIT; accum_bit_offset += bit_offset; } else return region_offset::make_symbolic (iter_region); } continue; case RK_CAST: { const cast_region *cast_reg = as_a (iter_region); iter_region = cast_reg->get_original_region (); } continue; default: return region_offset::make_concrete (iter_region, accum_bit_offset); } } return region_offset::make_concrete (iter_region, accum_bit_offset); } /* Copy from SRC_REG to DST_REG, using CTXT for any issues that occur. */ void region_model::copy_region (const region *dst_reg, const region *src_reg, region_model_context *ctxt) { gcc_assert (dst_reg); gcc_assert (src_reg); if (dst_reg == src_reg) return; const svalue *sval = get_store_value (src_reg); set_value (dst_reg, sval, ctxt); } /* Dump a description of this region to stderr. */ DEBUG_FUNCTION void region::dump (bool simple) const { pretty_printer pp; pp_format_decoder (&pp) = default_tree_printer; pp_show_color (&pp) = pp_show_color (global_dc->printer); pp.buffer->stream = stderr; dump_to_pp (&pp, simple); pp_newline (&pp); pp_flush (&pp); } /* Return a new json::string describing the region. */ json::value * region::to_json () const { label_text desc = get_desc (true); json::value *reg_js = new json::string (desc.m_buffer); desc.maybe_free (); return reg_js; } /* Generate a description of this region. */ DEBUG_FUNCTION label_text region::get_desc (bool simple) const { pretty_printer pp; pp_format_decoder (&pp) = default_tree_printer; dump_to_pp (&pp, simple); return label_text::take (xstrdup (pp_formatted_text (&pp))); } /* Base implementation of region::accept vfunc. Subclass implementations should chain up to this. */ void region::accept (visitor *v) const { v->visit_region (this); if (m_parent) m_parent->accept (v); } /* Return true if this is a symbolic region for deferencing an unknown ptr. We shouldn't attempt to bind values for this region (but can unbind values for other regions). */ bool region::symbolic_for_unknown_ptr_p () const { if (const symbolic_region *sym_reg = dyn_cast_symbolic_region ()) if (sym_reg->get_pointer ()->get_kind () == SK_UNKNOWN) return true; return false; } /* region's ctor. */ region::region (complexity c, unsigned id, const region *parent, tree type) : m_complexity (c), m_id (id), m_parent (parent), m_type (type), m_cached_offset (NULL) { gcc_assert (type == NULL_TREE || TYPE_P (type)); } /* Comparator for use by vec::qsort, using their IDs to order them. */ int region::cmp_ptr_ptr (const void *p1, const void *p2) { const region * const *reg1 = (const region * const *)p1; const region * const *reg2 = (const region * const *)p2; return cmp_ids (*reg1, *reg2); } /* Determine if a pointer to this region must be non-NULL. Generally, pointers to regions must be non-NULL, but pointers to symbolic_regions might, in fact, be NULL. This allows us to simulate functions like malloc and calloc with: - only one "outcome" from each statement, - the idea that the pointer is on the heap if non-NULL - the possibility that the pointer could be NULL - the idea that successive values returned from malloc are non-equal - to be able to zero-fill for calloc. */ bool region::non_null_p () const { switch (get_kind ()) { default: return true; case RK_SYMBOLIC: /* Are we within a symbolic_region? If so, it could be NULL, and we have to fall back on the constraints. */ return false; case RK_HEAP_ALLOCATED: return false; } } /* Comparator for trees to impose a deterministic ordering on T1 and T2. */ static int tree_cmp (const_tree t1, const_tree t2) { gcc_assert (t1); gcc_assert (t2); /* Test tree codes first. */ if (TREE_CODE (t1) != TREE_CODE (t2)) return TREE_CODE (t1) - TREE_CODE (t2); /* From this point on, we know T1 and T2 have the same tree code. */ if (DECL_P (t1)) { if (DECL_NAME (t1) && DECL_NAME (t2)) return strcmp (IDENTIFIER_POINTER (DECL_NAME (t1)), IDENTIFIER_POINTER (DECL_NAME (t2))); else { if (DECL_NAME (t1)) return -1; else if (DECL_NAME (t2)) return 1; else return DECL_UID (t1) - DECL_UID (t2); } } switch (TREE_CODE (t1)) { case SSA_NAME: { if (SSA_NAME_VAR (t1) && SSA_NAME_VAR (t2)) { int var_cmp = tree_cmp (SSA_NAME_VAR (t1), SSA_NAME_VAR (t2)); if (var_cmp) return var_cmp; return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2); } else { if (SSA_NAME_VAR (t1)) return -1; else if (SSA_NAME_VAR (t2)) return 1; else return SSA_NAME_VERSION (t1) - SSA_NAME_VERSION (t2); } } break; case INTEGER_CST: return tree_int_cst_compare (t1, t2); case REAL_CST: { const real_value *rv1 = TREE_REAL_CST_PTR (t1); const real_value *rv2 = TREE_REAL_CST_PTR (t2); if (real_compare (UNORDERED_EXPR, rv1, rv2)) { /* Impose an arbitrary order on NaNs relative to other NaNs and to non-NaNs. */ if (int cmp_isnan = real_isnan (rv1) - real_isnan (rv2)) return cmp_isnan; if (int cmp_issignaling_nan = real_issignaling_nan (rv1) - real_issignaling_nan (rv2)) return cmp_issignaling_nan; return real_isneg (rv1) - real_isneg (rv2); } if (real_compare (LT_EXPR, rv1, rv2)) return -1; if (real_compare (GT_EXPR, rv1, rv2)) return 1; return 0; } case STRING_CST: return strcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2)); default: gcc_unreachable (); break; } gcc_unreachable (); return 0; } /* qsort comparator for trees to impose a deterministic ordering on P1 and P2. */ int tree_cmp (const void *p1, const void *p2) { const_tree t1 = *(const_tree const *)p1; const_tree t2 = *(const_tree const *)p2; return tree_cmp (t1, t2); } /* class frame_region : public space_region. */ frame_region::~frame_region () { for (map_t::iterator iter = m_locals.begin (); iter != m_locals.end (); ++iter) delete (*iter).second; } void frame_region::accept (visitor *v) const { region::accept (v); if (m_calling_frame) m_calling_frame->accept (v); } /* Implementation of region::dump_to_pp vfunc for frame_region. */ void frame_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_printf (pp, "frame: %qs@%i", function_name (m_fun), get_stack_depth ()); else 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) const { // TODO: could also check that VAR_DECLs are locals gcc_assert (TREE_CODE (expr) == PARM_DECL || TREE_CODE (expr) == VAR_DECL || TREE_CODE (expr) == SSA_NAME || TREE_CODE (expr) == RESULT_DECL); /* Ideally we'd use mutable here. */ map_t &mutable_locals = const_cast (m_locals); if (decl_region **slot = mutable_locals.get (expr)) return *slot; decl_region *reg = new decl_region (mgr->alloc_region_id (), this, expr); mutable_locals.put (expr, reg); return reg; } /* class globals_region : public space_region. */ /* Implementation of region::dump_to_pp vfunc for globals_region. */ void globals_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "::"); else pp_string (pp, "globals"); } /* class code_region : public map_region. */ /* Implementation of region::dump_to_pp vfunc for code_region. */ void code_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "code region"); else pp_string (pp, "code_region()"); } /* class function_region : public region. */ /* Implementation of region::dump_to_pp vfunc for function_region. */ void function_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { dump_quoted_tree (pp, m_fndecl); } else { pp_string (pp, "function_region("); dump_quoted_tree (pp, m_fndecl); pp_string (pp, ")"); } } /* class label_region : public region. */ /* Implementation of region::dump_to_pp vfunc for label_region. */ void label_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { dump_quoted_tree (pp, m_label); } else { 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. */ void stack_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "stack region"); else pp_string (pp, "stack_region()"); } /* class heap_region : public region. */ /* Implementation of region::dump_to_pp vfunc for heap_region. */ void heap_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "heap region"); else pp_string (pp, "heap_region()"); } /* class root_region : public region. */ /* root_region's ctor. */ root_region::root_region (unsigned id) : region (complexity (1, 1), id, NULL, NULL_TREE) { } /* Implementation of region::dump_to_pp vfunc for root_region. */ void root_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "root region"); else pp_string (pp, "root_region()"); } /* class symbolic_region : public map_region. */ /* symbolic_region's ctor. */ symbolic_region::symbolic_region (unsigned id, region *parent, const svalue *sval_ptr) : region (complexity::from_pair (parent, sval_ptr), id, parent, TREE_TYPE (sval_ptr->get_type ())), m_sval_ptr (sval_ptr) { } /* Implementation of region::accept vfunc for symbolic_region. */ void symbolic_region::accept (visitor *v) const { region::accept (v); m_sval_ptr->accept (v); } /* Implementation of region::dump_to_pp vfunc for symbolic_region. */ void symbolic_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { pp_string (pp, "(*"); m_sval_ptr->dump_to_pp (pp, simple); pp_string (pp, ")"); } else { pp_string (pp, "symbolic_region("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_string (pp, ", "); m_sval_ptr->dump_to_pp (pp, simple); pp_string (pp, ")"); } } /* class decl_region : public region. */ /* Implementation of region::dump_to_pp vfunc for decl_region. */ void decl_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_printf (pp, "%E", m_decl); else { pp_string (pp, "decl_region("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_printf (pp, ", %qE)", m_decl); } } /* Get the stack depth for the frame containing this decl, or 0 for a global. */ int decl_region::get_stack_depth () const { if (get_parent_region () == NULL) return 0; if (const frame_region *frame_reg = get_parent_region ()->dyn_cast_frame_region ()) return frame_reg->get_stack_depth (); return 0; } /* If the underlying decl is in the global constant pool, return an svalue representing the constant value. Otherwise return NULL. */ const svalue * decl_region::maybe_get_constant_value (region_model_manager *mgr) const { if (TREE_CODE (m_decl) == VAR_DECL && DECL_IN_CONSTANT_POOL (m_decl) && DECL_INITIAL (m_decl) && TREE_CODE (DECL_INITIAL (m_decl)) == CONSTRUCTOR) return get_svalue_for_constructor (DECL_INITIAL (m_decl), mgr); return NULL; } /* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl. */ const svalue * decl_region::get_svalue_for_constructor (tree ctor, region_model_manager *mgr) const { gcc_assert (!TREE_CLOBBER_P (ctor)); /* Create a binding map, applying ctor to it, using this decl_region as the base region when building child regions for offset calculations. */ binding_map map; if (!map.apply_ctor_to_region (this, ctor, mgr)) return mgr->get_or_create_unknown_svalue (get_type ()); /* Return a compound svalue for the map we built. */ return mgr->get_or_create_compound_svalue (get_type (), map); } /* For use on decl_regions for global variables. Get an svalue for the initial value of this region at entry to "main" (either based on DECL_INITIAL, or implicit initialization to zero. Return NULL if there is a problem. */ const svalue * decl_region::get_svalue_for_initializer (region_model_manager *mgr) const { tree init = DECL_INITIAL (m_decl); if (!init) { /* If we have an "extern" decl then there may be an initializer in another TU. */ if (DECL_EXTERNAL (m_decl)) return NULL; /* Implicit initialization to zero; use a compound_svalue for it. Doing so requires that we have a concrete binding for this region, which can fail if we have a region with unknown size (e.g. "extern const char arr[];"). */ const binding_key *binding = binding_key::make (mgr->get_store_manager (), this, BK_direct); if (binding->symbolic_p ()) return NULL; binding_cluster c (this); c.zero_fill_region (mgr->get_store_manager (), this); return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl), c.get_map ()); } if (TREE_CODE (init) == CONSTRUCTOR) return get_svalue_for_constructor (init, mgr); /* Reuse the get_rvalue logic from region_model. */ region_model m (mgr); return m.get_rvalue (path_var (init, 0), NULL); } /* class field_region : public region. */ /* Implementation of region::dump_to_pp vfunc for field_region. */ void field_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, "."); pp_printf (pp, "%E", m_field); } else { pp_string (pp, "field_region("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_printf (pp, ", %qE)", m_field); } } /* class element_region : public region. */ /* Implementation of region::accept vfunc for element_region. */ void element_region::accept (visitor *v) const { region::accept (v); m_index->accept (v); } /* Implementation of region::dump_to_pp vfunc for element_region. */ void element_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { //pp_string (pp, "("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, "["); m_index->dump_to_pp (pp, simple); pp_string (pp, "]"); //pp_string (pp, ")"); } else { pp_string (pp, "element_region("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_string (pp, ", "); m_index->dump_to_pp (pp, simple); pp_printf (pp, ")"); } } /* class offset_region : public region. */ /* Implementation of region::accept vfunc for offset_region. */ void offset_region::accept (visitor *v) const { region::accept (v); m_byte_offset->accept (v); } /* Implementation of region::dump_to_pp vfunc for offset_region. */ void offset_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { //pp_string (pp, "("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, "+"); m_byte_offset->dump_to_pp (pp, simple); //pp_string (pp, ")"); } else { pp_string (pp, "offset_region("); get_parent_region ()->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_string (pp, ", "); m_byte_offset->dump_to_pp (pp, simple); pp_printf (pp, ")"); } } /* class cast_region : public region. */ /* Implementation of region::accept vfunc for cast_region. */ void cast_region::accept (visitor *v) const { region::accept (v); m_original_region->accept (v); } /* Implementation of region::dump_to_pp vfunc for cast_region. */ void cast_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) { pp_string (pp, "CAST_REG("); print_quoted_type (pp, get_type ()); pp_string (pp, ", "); m_original_region->dump_to_pp (pp, simple); pp_string (pp, ")"); } else { pp_string (pp, "cast_region("); m_original_region->dump_to_pp (pp, simple); pp_string (pp, ", "); print_quoted_type (pp, get_type ()); pp_printf (pp, ")"); } } /* class heap_allocated_region : public region. */ /* Implementation of region::dump_to_pp vfunc for heap_allocated_region. */ void heap_allocated_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_printf (pp, "HEAP_ALLOCATED_REGION(%i)", get_id ()); else pp_printf (pp, "heap_allocated_region(%i)", get_id ()); } /* class alloca_region : public region. */ /* Implementation of region::dump_to_pp vfunc for alloca_region. */ void alloca_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) pp_string (pp, "ALLOCA_REGION"); else pp_string (pp, "alloca_region()"); } /* class string_region : public region. */ /* Implementation of region::dump_to_pp vfunc for string_region. */ void string_region::dump_to_pp (pretty_printer *pp, bool simple) const { if (simple) dump_tree (pp, m_string_cst); else { pp_string (pp, "string_region("); dump_tree (pp, m_string_cst); if (!flag_dump_noaddr) { pp_string (pp, " ("); pp_pointer (pp, m_string_cst); pp_string (pp, "))"); } } } /* class unknown_region : public region. */ /* Implementation of region::dump_to_pp vfunc for unknown_region. */ void unknown_region::dump_to_pp (pretty_printer *pp, bool /*simple*/) const { pp_string (pp, "UNKNOWN_REGION"); } } // namespace ana #endif /* #if ENABLE_ANALYZER */