aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/analyzer.h1
-rw-r--r--gcc/analyzer/region-model-manager.cc20
-rw-r--r--gcc/analyzer/region-model.cc14
-rw-r--r--gcc/analyzer/region-model.h4
-rw-r--r--gcc/analyzer/region.cc84
-rw-r--r--gcc/analyzer/region.h89
6 files changed, 212 insertions, 0 deletions
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index c5bca2d..7e58bcd 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -67,6 +67,7 @@ class region;
class cast_region;
class field_region;
class string_region;
+ class bit_range_region;
class region_model_manager;
struct model_merger;
class store_manager;
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index ba835cb..010ad07 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -1494,6 +1494,25 @@ region_model_manager::get_region_for_string (tree string_cst)
return reg;
}
+/* Return the region that describes accessing BITS within PARENT as TYPE,
+ creating it if necessary. */
+
+const region *
+region_model_manager::get_bit_range (const region *parent, tree type,
+ const bit_range &bits)
+{
+ gcc_assert (parent);
+
+ bit_range_region::key_t key (parent, type, bits);
+ if (bit_range_region *reg = m_bit_range_regions.get (key))
+ return reg;
+
+ bit_range_region *bit_range_reg
+ = new bit_range_region (alloc_region_id (), parent, type, bits);
+ m_bit_range_regions.put (key, bit_range_reg);
+ return bit_range_reg;
+}
+
/* If we see a tree code we don't know how to handle, rather than
ICE or generate bogus results, create a dummy region, and notify
CTXT so that it can mark the new state as being not properly
@@ -1663,6 +1682,7 @@ region_model_manager::log_stats (logger *logger, bool show_objs) const
log_uniq_map (logger, show_objs, "frame_region", m_frame_regions);
log_uniq_map (logger, show_objs, "symbolic_region", m_symbolic_regions);
log_uniq_map (logger, show_objs, "string_region", m_string_map);
+ log_uniq_map (logger, show_objs, "bit_range_region", m_bit_range_regions);
logger->log (" # managed dynamic regions: %i",
m_managed_dynamic_regions.length ());
m_store_mgr.log_stats (logger, show_objs);
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 4c312b0..58c7028 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1707,6 +1707,20 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt) const
}
break;
+ case BIT_FIELD_REF:
+ {
+ tree inner_expr = TREE_OPERAND (expr, 0);
+ const region *inner_reg = get_lvalue (inner_expr, ctxt);
+ tree num_bits = TREE_OPERAND (expr, 1);
+ tree first_bit_offset = TREE_OPERAND (expr, 2);
+ gcc_assert (TREE_CODE (num_bits) == INTEGER_CST);
+ gcc_assert (TREE_CODE (first_bit_offset) == INTEGER_CST);
+ bit_range bits (TREE_INT_CST_LOW (first_bit_offset),
+ TREE_INT_CST_LOW (num_bits));
+ return m_mgr->get_bit_range (inner_reg, TREE_TYPE (expr), bits);
+ }
+ break;
+
case MEM_REF:
{
tree ptr = TREE_OPERAND (expr, 0);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 983d082..3fa090d 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -318,6 +318,8 @@ public:
function *fun);
const region *get_symbolic_region (const svalue *sval);
const string_region *get_region_for_string (tree string_cst);
+ const region *get_bit_range (const region *parent, tree type,
+ const bit_range &bits);
const region *
get_region_for_unexpected_tree_code (region_model_context *ctxt,
@@ -471,6 +473,8 @@ private:
typedef hash_map<tree, string_region *> string_map_t;
string_map_t m_string_map;
+ consolidation_map<bit_range_region> m_bit_range_regions;
+
store_manager m_store_mgr;
bounded_ranges_manager *m_range_mgr;
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index f5a2a0b..9d8fdb2 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -99,6 +99,7 @@ region::get_base_region () const
case RK_ELEMENT:
case RK_OFFSET:
case RK_SIZED:
+ case RK_BIT_RANGE:
iter = iter->get_parent_region ();
continue;
case RK_CAST:
@@ -124,6 +125,7 @@ region::base_region_p () const
case RK_OFFSET:
case RK_SIZED:
case RK_CAST:
+ case RK_BIT_RANGE:
return false;
default:
@@ -547,6 +549,19 @@ region::calc_offset () const
}
continue;
+ case RK_BIT_RANGE:
+ {
+ const bit_range_region *bit_range_reg
+ = (const bit_range_region *)iter_region;
+ iter_region = iter_region->get_parent_region ();
+
+ bit_offset_t rel_bit_offset;
+ if (!bit_range_reg->get_relative_concrete_offset (&rel_bit_offset))
+ return region_offset::make_symbolic (iter_region);
+ accum_bit_offset += rel_bit_offset;
+ }
+ continue;
+
default:
return region_offset::make_concrete (iter_region, accum_bit_offset);
}
@@ -1446,6 +1461,75 @@ string_region::dump_to_pp (pretty_printer *pp, bool simple) const
}
}
+/* class bit_range_region : public region. */
+
+/* Implementation of region::dump_to_pp vfunc for bit_range_region. */
+
+void
+bit_range_region::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+ if (simple)
+ {
+ pp_string (pp, "BIT_RANGE_REG(");
+ get_parent_region ()->dump_to_pp (pp, simple);
+ pp_string (pp, ", ");
+ m_bits.dump_to_pp (pp);
+ pp_string (pp, ")");
+ }
+ else
+ {
+ pp_string (pp, "bit_range_region(");
+ get_parent_region ()->dump_to_pp (pp, simple);
+ pp_string (pp, ", ");
+ m_bits.dump_to_pp (pp);
+ pp_printf (pp, ")");
+ }
+}
+
+/* Implementation of region::get_byte_size vfunc for bit_range_region. */
+
+bool
+bit_range_region::get_byte_size (byte_size_t *out) const
+{
+ if (m_bits.m_size_in_bits % BITS_PER_UNIT == 0)
+ {
+ *out = m_bits.m_size_in_bits / BITS_PER_UNIT;
+ return true;
+ }
+ return false;
+}
+
+/* Implementation of region::get_bit_size vfunc for bit_range_region. */
+
+bool
+bit_range_region::get_bit_size (bit_size_t *out) const
+{
+ *out = m_bits.m_size_in_bits;
+ return true;
+}
+
+/* Implementation of region::get_byte_size_sval vfunc for bit_range_region. */
+
+const svalue *
+bit_range_region::get_byte_size_sval (region_model_manager *mgr) const
+{
+ if (m_bits.m_size_in_bits % BITS_PER_UNIT != 0)
+ return mgr->get_or_create_unknown_svalue (size_type_node);
+
+ HOST_WIDE_INT num_bytes = m_bits.m_size_in_bits.to_shwi () / BITS_PER_UNIT;
+ return mgr->get_or_create_int_cst (size_type_node, num_bytes);
+}
+
+/* Implementation of region::get_relative_concrete_offset vfunc for
+ bit_range_region. */
+
+bool
+bit_range_region::get_relative_concrete_offset (bit_offset_t *out) const
+{
+ *out = m_bits.get_start_bit_offset ();
+ return true;
+}
+
/* class unknown_region : public region. */
/* Implementation of region::dump_to_pp vfunc for unknown_region. */
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 20eca52..206b157 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -60,6 +60,7 @@ enum region_kind
RK_HEAP_ALLOCATED,
RK_ALLOCA,
RK_STRING,
+ RK_BIT_RANGE,
RK_UNKNOWN
};
@@ -88,6 +89,7 @@ enum region_kind
heap_allocated_region (RK_HEAP_ALLOCATED)
alloca_region (RK_ALLOCA)
string_region (RK_STRING)
+ bit_range_region (RK_BIT_RANGE)
unknown_region (RK_UNKNOWN). */
/* Abstract base class for representing ways of accessing chunks of memory.
@@ -127,6 +129,8 @@ public:
dyn_cast_cast_region () const { return NULL; }
virtual const string_region *
dyn_cast_string_region () const { return NULL; }
+ virtual const bit_range_region *
+ dyn_cast_bit_range_region () const { return NULL; }
virtual void accept (visitor *v) const;
@@ -1133,6 +1137,91 @@ is_a_helper <const string_region *>::test (const region *reg)
namespace ana {
+/* A region for a specific range of bits within another region. */
+
+class bit_range_region : public region
+{
+public:
+ /* A support class for uniquifying instances of bit_range_region. */
+ struct key_t
+ {
+ key_t (const region *parent, tree type, const bit_range &bits)
+ : m_parent (parent), m_type (type), m_bits (bits)
+ {
+ gcc_assert (parent);
+ }
+
+ hashval_t hash () const
+ {
+ inchash::hash hstate;
+ hstate.add_ptr (m_parent);
+ hstate.add_ptr (m_type);
+ hstate.add (&m_bits, sizeof (m_bits));
+ return hstate.end ();
+ }
+
+ bool operator== (const key_t &other) const
+ {
+ return (m_parent == other.m_parent
+ && m_type == other.m_type
+ && m_bits == other.m_bits);
+ }
+
+ void mark_deleted () { m_parent = reinterpret_cast<const region *> (1); }
+ void mark_empty () { m_parent = NULL; }
+ bool is_deleted () const
+ {
+ return m_parent == reinterpret_cast<const region *> (1);
+ }
+ bool is_empty () const { return m_parent == NULL; }
+
+ const region *m_parent;
+ tree m_type;
+ bit_range m_bits;
+ };
+
+ bit_range_region (unsigned id, const region *parent, tree type,
+ const bit_range &bits)
+ : region (complexity (parent), id, parent, type),
+ m_bits (bits)
+ {}
+
+ const bit_range_region *
+ dyn_cast_bit_range_region () const FINAL OVERRIDE { return this; }
+
+ enum region_kind get_kind () const FINAL OVERRIDE { return RK_BIT_RANGE; }
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
+
+ const bit_range &get_bits () const { return m_bits; }
+
+ bool get_byte_size (byte_size_t *out) const FINAL OVERRIDE;
+ bool get_bit_size (bit_size_t *out) const FINAL OVERRIDE;
+ const svalue *get_byte_size_sval (region_model_manager *mgr) const FINAL OVERRIDE;
+ bool get_relative_concrete_offset (bit_offset_t *out) const FINAL OVERRIDE;
+
+private:
+ bit_range m_bits;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const bit_range_region *>::test (const region *reg)
+{
+ return reg->get_kind () == RK_BIT_RANGE;
+}
+
+template <> struct default_hash_traits<bit_range_region::key_t>
+: public member_function_hash_traits<bit_range_region::key_t>
+{
+ static const bool empty_zero_p = true;
+};
+
+namespace ana {
+
/* An unknown region, for handling unimplemented tree codes. */
class unknown_region : public region