LCOV - code coverage report
Current view: top level - gcc/analyzer - access-diagram.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 85.9 % 1243 1068
Test Date: 2024-04-27 14:03:13 Functions: 88.2 % 93 82
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Text art visualizations within -fanalyzer.
       2                 :             :    Copyright (C) 2023-2024 Free Software Foundation, Inc.
       3                 :             : 
       4                 :             : This file is part of GCC.
       5                 :             : 
       6                 :             : GCC is free software; you can redistribute it and/or modify it
       7                 :             : under the terms of the GNU General Public License as published by
       8                 :             : the Free Software Foundation; either version 3, or (at your option)
       9                 :             : any later version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful, but
      12                 :             : WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14                 :             : General Public License for more details.
      15                 :             : 
      16                 :             : You should have received a copy of the GNU General Public License
      17                 :             : along with GCC; see the file COPYING3.  If not see
      18                 :             : <http://www.gnu.org/licenses/>.  */
      19                 :             : 
      20                 :             : #include "config.h"
      21                 :             : #define INCLUDE_ALGORITHM
      22                 :             : #define INCLUDE_MEMORY
      23                 :             : #define INCLUDE_MAP
      24                 :             : #define INCLUDE_SET
      25                 :             : #define INCLUDE_VECTOR
      26                 :             : #include "system.h"
      27                 :             : #include "coretypes.h"
      28                 :             : #include "coretypes.h"
      29                 :             : #include "tree.h"
      30                 :             : #include "function.h"
      31                 :             : #include "basic-block.h"
      32                 :             : #include "gimple.h"
      33                 :             : #include "diagnostic-core.h"
      34                 :             : #include "diagnostic.h"
      35                 :             : #include "intl.h"
      36                 :             : #include "make-unique.h"
      37                 :             : #include "tree-diagnostic.h" /* for default_tree_printer.  */
      38                 :             : #include "analyzer/analyzer.h"
      39                 :             : #include "analyzer/region-model.h"
      40                 :             : #include "analyzer/access-diagram.h"
      41                 :             : #include "text-art/ruler.h"
      42                 :             : #include "fold-const.h"
      43                 :             : #include "analyzer/analyzer-selftests.h"
      44                 :             : 
      45                 :             : #if ENABLE_ANALYZER
      46                 :             : 
      47                 :             : /* Consider this code:
      48                 :             :      int32_t arr[10];
      49                 :             :      arr[10] = x;
      50                 :             :    where we've emitted a buffer overflow diagnostic like this:
      51                 :             :      out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
      52                 :             : 
      53                 :             :    We want to emit a diagram that visualizes:
      54                 :             :    - the spatial relationship between the valid region to access, versus
      55                 :             :    the region that was actually accessed: does it overlap, was it touching,
      56                 :             :    close, or far away?  Was it before or after in memory?  What are the
      57                 :             :    relative sizes involved?
      58                 :             :    - the direction of the access (read vs write)
      59                 :             : 
      60                 :             :    The following code supports emitting diagrams similar to the following:
      61                 :             : 
      62                 :             :    #                                        +--------------------------------+
      63                 :             :    #                                        |write from ‘x’ (type: ‘int32_t’)|
      64                 :             :    #                                        +--------------------------------+
      65                 :             :    #                                                        |
      66                 :             :    #                                                        |
      67                 :             :    #                                                        v
      68                 :             :    #  +---------+-----------+-----------+   +--------------------------------+
      69                 :             :    #  |   [0]   |    ...    |    [9]    |   |       after valid range        |
      70                 :             :    #  +---------+-----------+-----------+   |                                |
      71                 :             :    #  |   ‘arr’ (type: ‘int32_t[10]’)   |   |                                |
      72                 :             :    #  +---------------------------------+   +--------------------------------+
      73                 :             :    #  |~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~|   |~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~|
      74                 :             :    #                   |                                    |
      75                 :             :    #         +---------+--------+                 +---------+---------+
      76                 :             :    #         |capacity: 40 bytes|                 |overflow of 4 bytes|
      77                 :             :    #         +------------------+                 +-------------------+
      78                 :             : 
      79                 :             :   where the diagram is laid out via table columns where each table column
      80                 :             :   represents either a range of bits/bytes, or is a spacing column (to highlight
      81                 :             :   the boundary between valid vs invalid accesses).  The table columns can be
      82                 :             :   seen via -fanalyzer-debug-text-art.  For example, here there are 5 table
      83                 :             :   columns ("tc0" through "tc4"):
      84                 :             : 
      85                 :             :    #  +---------+-----------+-----------+---+--------------------------------+
      86                 :             :    #  |   tc0   |    tc1    |    tc2    |tc3|              tc4               |
      87                 :             :    #  +---------+-----------+-----------+---+--------------------------------+
      88                 :             :    #  |bytes 0-3|bytes 4-35 |bytes 36-39|   |          bytes 40-43           |
      89                 :             :    #  +---------+-----------+-----------+   +--------------------------------+
      90                 :             :    #
      91                 :             :    #                                        +--------------------------------+
      92                 :             :    #                                        |write from ‘x’ (type: ‘int32_t’)|
      93                 :             :    #                                        +--------------------------------+
      94                 :             :    #                                                        |
      95                 :             :    #                                                        |
      96                 :             :    #                                                        v
      97                 :             :    #  +---------+-----------+-----------+   +--------------------------------+
      98                 :             :    #  |   [0]   |    ...    |    [9]    |   |       after valid range        |
      99                 :             :    #  +---------+-----------+-----------+   |                                |
     100                 :             :    #  |   ‘arr’ (type: ‘int32_t[10]’)   |   |                                |
     101                 :             :    #  +---------------------------------+   +--------------------------------+
     102                 :             :    #  |~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~|   |~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~|
     103                 :             :    #                   |                                    |
     104                 :             :    #         +---------+--------+                 +---------+---------+
     105                 :             :    #         |capacity: 40 bytes|                 |overflow of 4 bytes|
     106                 :             :    #         +------------------+                 +-------------------+
     107                 :             : 
     108                 :             :   The diagram is built up from the following:
     109                 :             : 
     110                 :             :    #                                        +--------------------------------+
     111                 :             :    #                                        | ITEM FOR SVALUE/ACCESSED REGION|
     112                 :             :    #                                        +--------------------------------+
     113                 :             :    #                                                        |
     114                 :             :    #                                                        | DIRECTION WIDGET
     115                 :             :    #                                                        v
     116                 :             :    #  +---------------------------------+   +--------------------------------+
     117                 :             :    #  |   VALID REGION                  |   | INVALID ACCESS                 |
     118                 :             :    #  +---------------------------------+   +--------------------------------+
     119                 :             :    #
     120                 :             :    #  |                       VALID-VS-INVALID RULER                         |
     121                 :             : 
     122                 :             :   i.e. a vbox_widget containing 4 child widgets laid out vertically:
     123                 :             :   - ALIGNED CHILD WIDGET: ITEM FOR SVALUE/ACCESSED REGION
     124                 :             :   - DIRECTION WIDGET
     125                 :             :   - ALIGNED CHILD WIDGET: VALID AND INVALID ACCESSES
     126                 :             :   - VALID-VS-INVALID RULER.
     127                 :             : 
     128                 :             :   A more complicated example, given this overflow:
     129                 :             :      char buf[100];
     130                 :             :      strcpy (buf, LOREM_IPSUM);
     131                 :             : 
     132                 :             :    01| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     133                 :             :    02| |[0]|[1]|[2]|[3]|[4]|[5]|   ...    |[440]|[441]|[442]|[443]|[444]|[445]|
     134                 :             :    03| +---+---+---+---+---+---+          +-----+-----+-----+-----+-----+-----+
     135                 :             :    04| |'L'|'o'|'r'|'e'|'m'|' '|          | 'o' | 'r' | 'u' | 'm' | '.' | NUL |
     136                 :             :    05| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     137                 :             :    06| |                  string literal (type: 'char[446]')                  |
     138                 :             :    07| +----------------------------------------------------------------------+
     139                 :             :    08|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     140                 :             :    09|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     141                 :             :    10|   v   v   v   v   v   v  v  v    v    v     v     v     v     v     v
     142                 :             :    11| +---+---------------------+----++--------------------------------------+
     143                 :             :    12| |[0]|         ...         |[99]||          after valid range           |
     144                 :             :    13| +---+---------------------+----+|                                      |
     145                 :             :    14| |  'buf' (type: 'char[100]')   ||                                      |
     146                 :             :    15| +------------------------------++--------------------------------------+
     147                 :             :    16| |~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~||~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~|
     148                 :             :    17|                |                                   |
     149                 :             :    18|      +---------+---------+              +----------+----------+
     150                 :             :    19|      |capacity: 100 bytes|              |overflow of 346 bytes|
     151                 :             :    20|      +-------------------+              +---------------------+
     152                 :             : 
     153                 :             :  which is:
     154                 :             : 
     155                 :             :    01| ALIGNED CHILD WIDGET (lines 01-07): (string_region_spatial_item)-+-----+
     156                 :             :    02| |[0]|[1]|[2]|[3]|[4]|[5]|   ...    |[440]|[441]|[442]|[443]|[444]|[445]|
     157                 :             :    03| +---+---+---+---+---+---+          +-----+-----+-----+-----+-----+-----+
     158                 :             :    04| |'L'|'o'|'r'|'e'|'m'|' '|          | 'o' | 'r' | 'u' | 'm' | '.' | NUL |
     159                 :             :    05| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     160                 :             :    06| |                  string literal (type: 'char[446]')                  |
     161                 :             :    07| +----------------------------------------------------------------------+
     162                 :             :    08| DIRECTION WIDGET (lines 08-10)   |    |     |     |     |     |     |
     163                 :             :    09|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     164                 :             :    10|   v   v   v   v   v   v  v  v    v    v     v     v     v     v     v
     165                 :             :    11| ALIGNED CHILD WIDGET (lines 11-15)-------------------------------------+
     166                 :             :    12| VALID REGION  ...         |[99]|| INVALID ACCESS                       |
     167                 :             :    13| +---+---------------------+----+|                                      |
     168                 :             :    14| |  'buf' (type: 'char[100]')   ||                                      |
     169                 :             :    15| +------------------------------++--------------------------------------+
     170                 :             :    16| VALID-VS-INVALID RULER (lines 16-20): ~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~|
     171                 :             :    17|                |                                   |
     172                 :             :    18|      +---------+---------+              +----------+----------+
     173                 :             :    19|      |capacity: 100 bytes|              |overflow of 346 bytes|
     174                 :             :    20|      +-------------------+              +---------------------+
     175                 :             : 
     176                 :             :    We build the diagram in several phases:
     177                 :             :    - (1) we construct an access_diagram_impl widget.  Within the ctor, we have
     178                 :             :    these subphases:
     179                 :             :    -   (1.1) find all of the boundaries of interest
     180                 :             :    -   (1.2) use the boundaries to build a bit_table_map, associating bit ranges
     181                 :             :    with table columns (e.g. "byte 0 is column 0, bytes 1-98 are column 2" etc)
     182                 :             :    -   (1.3) create child widgets that share this table-based geometry
     183                 :             :    - (2) ask the widget for its size request
     184                 :             :    -   (2.1) column widths and row heights for the table are computed by
     185                 :             :    access_diagram_impl::calc_req_size
     186                 :             :    -   (2.2) child widgets request sizes based on these widths/heights
     187                 :             :    - (3) create a canvas of the appropriate size
     188                 :             :    - (4) paint the widget hierarchy to the canvas.  */
     189                 :             : 
     190                 :             : 
     191                 :             : using namespace text_art;
     192                 :             : 
     193                 :             : namespace ana {
     194                 :             : 
     195                 :             : static styled_string
     196                 :             : fmt_styled_string (style_manager &sm,
     197                 :             :                    const char *fmt, ...)
     198                 :             :     ATTRIBUTE_GCC_DIAG(2, 3);
     199                 :             : 
     200                 :             : static styled_string
     201                 :         824 : fmt_styled_string (style_manager &sm,
     202                 :             :                    const char *fmt, ...)
     203                 :             : {
     204                 :         824 :   va_list ap;
     205                 :         824 :   va_start (ap, fmt);
     206                 :         824 :   styled_string result
     207                 :         824 :     = styled_string::from_fmt_va (sm, default_tree_printer, fmt, &ap);
     208                 :         824 :   va_end (ap);
     209                 :         824 :   return result;
     210                 :             : }
     211                 :             : 
     212                 :             : class access_diagram_impl;
     213                 :             : class bit_to_table_map;
     214                 :             : 
     215                 :             : static void
     216                 :           2 : pp_bit_size_t (pretty_printer *pp, bit_size_t num_bits)
     217                 :             : {
     218                 :           2 :   if (num_bits % BITS_PER_UNIT == 0)
     219                 :             :     {
     220                 :           2 :       byte_size_t num_bytes = num_bits / BITS_PER_UNIT;
     221                 :           2 :       if (num_bytes == 1)
     222                 :           0 :         pp_printf (pp, _("%wi byte"), num_bytes.to_uhwi ());
     223                 :             :       else
     224                 :           2 :         pp_printf (pp, _("%wi bytes"), num_bytes.to_uhwi ());
     225                 :             :     }
     226                 :             :   else
     227                 :             :     {
     228                 :           0 :       if (num_bits == 1)
     229                 :           0 :         pp_printf (pp, _("%wi bit"), num_bits.to_uhwi ());
     230                 :             :       else
     231                 :           0 :         pp_printf (pp, _("%wi bits"), num_bits.to_uhwi ());
     232                 :             :     }
     233                 :           2 : }
     234                 :             : 
     235                 :             : static styled_string
     236                 :          19 : get_access_size_str (style_manager &sm,
     237                 :             :                      const access_operation &op,
     238                 :             :                      access_range accessed_range,
     239                 :             :                      tree type)
     240                 :             : {
     241                 :          19 :   bit_size_expr num_bits (accessed_range.get_size (op.m_model.get_manager ()));
     242                 :          19 :   if (type)
     243                 :             :     {
     244                 :           2 :       styled_string s;
     245                 :           2 :       pretty_printer pp;
     246                 :           2 :       pp_format_decoder (&pp) = default_tree_printer;
     247                 :           2 :       if (num_bits.maybe_print_for_user (&pp, op.m_model))
     248                 :             :         {
     249                 :           2 :           if (op.m_dir == DIR_READ)
     250                 :           2 :             return fmt_styled_string (sm,
     251                 :           2 :                                       _("read of %qT (%s)"),
     252                 :             :                                       type,
     253                 :           2 :                                       pp_formatted_text (&pp));
     254                 :             :           else
     255                 :           0 :             return fmt_styled_string (sm,
     256                 :           0 :                                       _("write of %qT (%s)"),
     257                 :             :                                       type,
     258                 :           0 :                                       pp_formatted_text (&pp));
     259                 :             :         }
     260                 :           2 :     }
     261                 :          17 :   if (op.m_dir == DIR_READ)
     262                 :             :     {
     263                 :          13 :       if (auto p
     264                 :             :           = num_bits.maybe_get_formatted_str (sm, op.m_model,
     265                 :          13 :                                               _("read of %wi bit"),
     266                 :          13 :                                               _("read of %wi bits"),
     267                 :          13 :                                               _("read of %wi byte"),
     268                 :          13 :                                               _("read of %wi bytes"),
     269                 :          13 :                                               _("read of %qs bits"),
     270                 :          13 :                                               _("read of %qs bytes")))
     271                 :          13 :         return std::move (*p.get ());
     272                 :             :     }
     273                 :             :   else
     274                 :             :     {
     275                 :           4 :       if (auto p
     276                 :             :           = num_bits.maybe_get_formatted_str (sm, op.m_model,
     277                 :           4 :                                               _("write of %wi bit"),
     278                 :           4 :                                               _("write of %wi bits"),
     279                 :           4 :                                               _("write of %wi byte"),
     280                 :           4 :                                               _("write of %wi bytes"),
     281                 :           4 :                                               _("write of %qs bits"),
     282                 :           4 :                                               _("write of %qs bytes")))
     283                 :           4 :         return std::move (*p.get ());
     284                 :             :     }
     285                 :             : 
     286                 :           0 :   if (type)
     287                 :             :     {
     288                 :           0 :       if (op.m_dir == DIR_READ)
     289                 :           0 :         return fmt_styled_string (sm, _("read of %qT"), type);
     290                 :             :       else
     291                 :           0 :         return fmt_styled_string (sm, _("write of %qT"), type);
     292                 :             :     }
     293                 :             : 
     294                 :           0 :   if (op.m_dir == DIR_READ)
     295                 :           0 :     return styled_string (sm, _("read"));
     296                 :             :   else
     297                 :           0 :     return styled_string (sm, _("write"));
     298                 :             : }
     299                 :             : 
     300                 :             : /* Subroutine of clean_up_for_diagram.  */
     301                 :             : 
     302                 :             : static tree
     303                 :           0 : strip_any_cast (tree expr)
     304                 :             : {
     305                 :           0 :   if (TREE_CODE (expr) == NOP_EXPR
     306                 :           0 :       || TREE_CODE (expr) == NON_LVALUE_EXPR)
     307                 :           0 :     expr = TREE_OPERAND (expr, 0);
     308                 :           0 :   return expr;
     309                 :             : }
     310                 :             : 
     311                 :             : /* Duplicate EXPR, replacing any SSA names with the underlying variable.  */
     312                 :             : 
     313                 :             : tree
     314                 :           5 : remove_ssa_names (tree expr)
     315                 :             : {
     316                 :           5 :   if (TREE_CODE (expr) == SSA_NAME
     317                 :           5 :       && SSA_NAME_VAR (expr))
     318                 :             :     return SSA_NAME_VAR (expr);
     319                 :           0 :   tree t = copy_node (expr);
     320                 :           0 :   for (int i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
     321                 :           0 :     if (TREE_OPERAND (expr, i))
     322                 :           0 :       TREE_OPERAND (t, i) = remove_ssa_names (TREE_OPERAND (expr, i));
     323                 :             :   return t;
     324                 :             : }
     325                 :             : 
     326                 :             : /* We want to be able to print tree expressions from the analyzer,
     327                 :             :    which is in the middle end.
     328                 :             : 
     329                 :             :    We could use the front-end pretty_printer's formatting routine,
     330                 :             :    but:
     331                 :             :    (a) some have additional state in a pretty_printer subclass, so we'd
     332                 :             :    need to clone global_dc->printer
     333                 :             :    (b) the "aka" type information added by the C and C++ frontends are
     334                 :             :    too verbose when building a diagram, and there isn't a good way to ask
     335                 :             :    for a less verbose version of them.
     336                 :             : 
     337                 :             :    Hence we use default_tree_printer.
     338                 :             :    However, we want to avoid printing SSA names, and instead print the
     339                 :             :    underlying var name.
     340                 :             :    Ideally there would be a better tree printer for use by middle end
     341                 :             :    warnings, but as workaround, this function clones a tree, replacing
     342                 :             :    SSA names with the var names.  */
     343                 :             : 
     344                 :             : tree
     345                 :           0 : clean_up_for_diagram (tree expr)
     346                 :             : {
     347                 :           0 :   tree without_ssa_names = remove_ssa_names (expr);
     348                 :           0 :   return strip_any_cast (without_ssa_names);
     349                 :             : }
     350                 :             : 
     351                 :             : /* struct bit_size_expr.  */
     352                 :             : 
     353                 :             : /* Attempt to generate a user-facing styled string that mentions this
     354                 :             :    bit_size_expr.
     355                 :             :    Use MODEL for extracting representative tree values where necessary.
     356                 :             :    The CONCRETE_* format strings should contain a single %wi.
     357                 :             :    The SYMBOLIC_* format strings should contain a single %qs.
     358                 :             :    Return nullptr if unable to represent the expression.  */
     359                 :             : 
     360                 :             : std::unique_ptr<text_art::styled_string>
     361                 :         174 : bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
     362                 :             :                                         const region_model &model,
     363                 :             :                                         const char *concrete_single_bit_fmt,
     364                 :             :                                         const char *concrete_plural_bits_fmt,
     365                 :             :                                         const char *concrete_single_byte_fmt,
     366                 :             :                                         const char *concrete_plural_bytes_fmt,
     367                 :             :                                         const char *symbolic_bits_fmt,
     368                 :             :                                         const char *symbolic_bytes_fmt) const
     369                 :             : {
     370                 :         174 :   region_model_manager &mgr = *model.get_manager ();
     371                 :         174 :   if (const svalue *num_bytes = maybe_get_as_bytes (mgr))
     372                 :             :     {
     373                 :         173 :       if (tree cst = num_bytes->maybe_get_constant ())
     374                 :             :         {
     375                 :         135 :           byte_size_t concrete_num_bytes = wi::to_offset (cst);
     376                 :         135 :           if (!wi::fits_uhwi_p (concrete_num_bytes))
     377                 :           0 :             return nullptr;
     378                 :         135 :           if (concrete_num_bytes == 1)
     379                 :          13 :             return ::make_unique <text_art::styled_string>
     380                 :          26 :               (fmt_styled_string (sm, concrete_single_byte_fmt,
     381                 :          13 :                                   concrete_num_bytes.to_uhwi ()));
     382                 :             :           else
     383                 :         122 :             return ::make_unique <text_art::styled_string>
     384                 :         244 :               (fmt_styled_string (sm, concrete_plural_bytes_fmt,
     385                 :         122 :                                   concrete_num_bytes.to_uhwi ()));
     386                 :             :         }
     387                 :             :       else
     388                 :             :         {
     389                 :          38 :           pretty_printer pp;
     390                 :          38 :           pp_format_decoder (&pp) = default_tree_printer;
     391                 :          38 :           if (!num_bytes->maybe_print_for_user (&pp, model))
     392                 :           0 :             return nullptr;
     393                 :          38 :           return ::make_unique <text_art::styled_string>
     394                 :          76 :             (fmt_styled_string (sm, symbolic_bytes_fmt,
     395                 :          38 :                                 pp_formatted_text (&pp)));
     396                 :          38 :         }
     397                 :             :     }
     398                 :           1 :   else if (tree cst = m_num_bits.maybe_get_constant ())
     399                 :             :     {
     400                 :           0 :       bit_size_t concrete_num_bits = wi::to_offset (cst);
     401                 :           0 :       if (!wi::fits_uhwi_p (concrete_num_bits))
     402                 :           0 :         return nullptr;
     403                 :           0 :       if (concrete_num_bits == 1)
     404                 :           0 :         return ::make_unique <text_art::styled_string>
     405                 :           0 :           (fmt_styled_string (sm, concrete_single_bit_fmt,
     406                 :           0 :                               concrete_num_bits.to_uhwi ()));
     407                 :             :       else
     408                 :           0 :         return ::make_unique <text_art::styled_string>
     409                 :           0 :           (fmt_styled_string (sm, concrete_plural_bits_fmt,
     410                 :           0 :                               concrete_num_bits.to_uhwi ()));
     411                 :             :     }
     412                 :             :   else
     413                 :             :     {
     414                 :           1 :       pretty_printer pp;
     415                 :           1 :       pp_format_decoder (&pp) = default_tree_printer;
     416                 :           1 :       if (!m_num_bits.maybe_print_for_user (&pp, model))
     417                 :           1 :         return nullptr;
     418                 :           0 :       return ::make_unique <text_art::styled_string>
     419                 :           0 :         (fmt_styled_string (sm, symbolic_bits_fmt,
     420                 :           0 :                             pp_formatted_text (&pp)));
     421                 :           1 :     }
     422                 :             : }
     423                 :             : 
     424                 :             : bool
     425                 :           2 : bit_size_expr::maybe_print_for_user (pretty_printer *pp,
     426                 :             :                                      const region_model &model) const
     427                 :             : {
     428                 :           2 :   if (tree cst = m_num_bits.maybe_get_constant ())
     429                 :             :     {
     430                 :           2 :       bit_size_t concrete_num_bits = wi::to_offset (cst);
     431                 :           2 :       pp_bit_size_t (pp, concrete_num_bits);
     432                 :           2 :       return true;
     433                 :             :     }
     434                 :             :   else
     435                 :             :     {
     436                 :           0 :       if (const svalue *num_bytes = maybe_get_as_bytes (*model.get_manager ()))
     437                 :             :         {
     438                 :           0 :           pretty_printer tmp_pp;
     439                 :           0 :           pp_format_decoder (&tmp_pp) = default_tree_printer;
     440                 :           0 :           if (!num_bytes->maybe_print_for_user (&tmp_pp, model))
     441                 :             :             return false;
     442                 :           0 :           pp_printf (pp, _("%qs bytes"), pp_formatted_text (&tmp_pp));
     443                 :           0 :           return true;
     444                 :           0 :         }
     445                 :             :       else
     446                 :             :         {
     447                 :           0 :           pretty_printer tmp_pp;
     448                 :           0 :           pp_format_decoder (&tmp_pp) = default_tree_printer;
     449                 :           0 :           if (!m_num_bits.maybe_print_for_user (&tmp_pp, model))
     450                 :             :             return false;
     451                 :           0 :           pp_printf (pp, _("%qs bits"), pp_formatted_text (&tmp_pp));
     452                 :           0 :           return true;
     453                 :           0 :         }
     454                 :             :     }
     455                 :             : }
     456                 :             : 
     457                 :             : /* Attempt to get a symbolic value for this symbolic bit size,
     458                 :             :    expressed in bytes.
     459                 :             :    Return null if it's not known to divide exactly.  */
     460                 :             : 
     461                 :             : const svalue *
     462                 :         190 : bit_size_expr::maybe_get_as_bytes (region_model_manager &mgr) const
     463                 :             : {
     464                 :         190 :   if (tree cst = m_num_bits.maybe_get_constant ())
     465                 :             :     {
     466                 :         143 :       bit_offset_t concrete_bits = wi::to_offset (cst);
     467                 :         143 :       if (concrete_bits % BITS_PER_UNIT != 0)
     468                 :             :         /* Not an exact multiple, so fail.  */
     469                 :           4 :         return nullptr;
     470                 :             :     }
     471                 :         186 :   const svalue *bits_per_byte
     472                 :         186 :     = mgr.get_or_create_int_cst (NULL_TREE, BITS_PER_UNIT);
     473                 :         186 :   return mgr.maybe_fold_binop (NULL_TREE, EXACT_DIV_EXPR,
     474                 :         186 :                                &m_num_bits, bits_per_byte);
     475                 :             : }
     476                 :             : 
     477                 :             : /* struct access_range.  */
     478                 :             : 
     479                 :        1240 : access_range::access_range (const region *base_region, const bit_range &bits)
     480                 :        1240 : : m_start (region_offset::make_concrete (base_region,
     481                 :             :                                          bits.get_start_bit_offset ())),
     482                 :        1240 :   m_next (region_offset::make_concrete (base_region,
     483                 :             :                                         bits.get_next_bit_offset ()))
     484                 :             : {
     485                 :        1240 : }
     486                 :             : 
     487                 :           0 : access_range::access_range (const region *base_region, const byte_range &bytes)
     488                 :           0 : : m_start (region_offset::make_concrete (base_region,
     489                 :             :                                          bytes.get_start_bit_offset ())),
     490                 :           0 :   m_next (region_offset::make_concrete (base_region,
     491                 :             :                                         bytes.get_next_bit_offset ()))
     492                 :             : {
     493                 :           0 : }
     494                 :             : 
     495                 :         662 : access_range::access_range (const region &reg, region_model_manager *mgr)
     496                 :         662 : : m_start (strip_types (reg.get_offset (mgr), *mgr)),
     497                 :         662 :   m_next (strip_types (reg.get_next_offset (mgr), *mgr))
     498                 :             : {
     499                 :         662 : }
     500                 :             : 
     501                 :             : bit_size_expr
     502                 :         159 : access_range::get_size (region_model_manager *mgr) const
     503                 :             : {
     504                 :         159 :   const svalue &start_bit_offset = m_start.calc_symbolic_bit_offset (mgr);
     505                 :         159 :   const svalue &next_bit_offset = m_next.calc_symbolic_bit_offset (mgr);
     506                 :         318 :   return bit_size_expr
     507                 :         159 :     (*mgr->get_or_create_binop (NULL_TREE, MINUS_EXPR,
     508                 :         159 :                                 &next_bit_offset, &start_bit_offset));
     509                 :             : }
     510                 :             : 
     511                 :             : bool
     512                 :         797 : access_range::contains_p (const access_range &other) const
     513                 :             : {
     514                 :         797 :   return (m_start <= other.m_start
     515                 :         797 :           && other.m_next <= m_next);
     516                 :             : }
     517                 :             : 
     518                 :             : bool
     519                 :         662 : access_range::empty_p () const
     520                 :             : {
     521                 :         662 :   bit_range concrete_bits (0, 0);
     522                 :         662 :   if (!as_concrete_bit_range (&concrete_bits))
     523                 :             :     return false;
     524                 :         546 :   return concrete_bits.empty_p ();
     525                 :             : }
     526                 :             : 
     527                 :             : void
     528                 :           4 : access_range::dump_to_pp (pretty_printer *pp, bool simple) const
     529                 :             : {
     530                 :           4 :   if (m_start.concrete_p () && m_next.concrete_p ())
     531                 :             :     {
     532                 :           4 :       bit_range bits (m_start.get_bit_offset (),
     533                 :           4 :                       m_next.get_bit_offset () - m_start.get_bit_offset ());
     534                 :           4 :       bits.dump_to_pp (pp);
     535                 :           4 :       return;
     536                 :             :     }
     537                 :           0 :   pp_character (pp, '[');
     538                 :           0 :   m_start.dump_to_pp (pp, simple);
     539                 :           0 :   pp_string (pp, " to ");
     540                 :           0 :   m_next.dump_to_pp (pp, simple);
     541                 :           0 :   pp_character (pp, ')');
     542                 :             : }
     543                 :             : 
     544                 :             : DEBUG_FUNCTION void
     545                 :           0 : access_range::dump (bool simple) const
     546                 :             : {
     547                 :           0 :   pretty_printer pp;
     548                 :           0 :   pp_format_decoder (&pp) = default_tree_printer;
     549                 :           0 :   pp_show_color (&pp) = pp_show_color (global_dc->printer);
     550                 :           0 :   pp.buffer->stream = stderr;
     551                 :           0 :   dump_to_pp (&pp, simple);
     552                 :           0 :   pp_newline (&pp);
     553                 :           0 :   pp_flush (&pp);
     554                 :           0 : }
     555                 :             : 
     556                 :             : void
     557                 :           0 : access_range::log (const char *title, logger &logger) const
     558                 :             : {
     559                 :           0 :   logger.start_log_line ();
     560                 :           0 :   logger.log_partial ("%s: ", title);
     561                 :           0 :   dump_to_pp (logger.get_printer (), true);
     562                 :           0 :   logger.end_log_line ();
     563                 :           0 : }
     564                 :             : 
     565                 :             : /* struct access_operation.  */
     566                 :             : 
     567                 :             : access_range
     568                 :        1419 : access_operation::get_valid_bits () const
     569                 :             : {
     570                 :        1419 :   const svalue *capacity_in_bytes_sval = m_model.get_capacity (m_base_region);
     571                 :        1419 :   return access_range
     572                 :        1419 :     (region_offset::make_concrete (m_base_region, 0),
     573                 :        1419 :      region_offset::make_byte_offset (m_base_region, capacity_in_bytes_sval),
     574                 :        2838 :      *get_manager ());
     575                 :             : }
     576                 :             : 
     577                 :             : access_range
     578                 :         578 : access_operation::get_actual_bits () const
     579                 :             : {
     580                 :         578 :   return access_range (m_reg, get_manager ());
     581                 :             : }
     582                 :             : 
     583                 :             : /* If there are any bits accessed invalidly before the valid range,
     584                 :             :    return true and write their range to *OUT.
     585                 :             :    Return false if there aren't, or if there's a problem
     586                 :             :    (e.g. symbolic ranges.  */
     587                 :             : 
     588                 :             : bool
     589                 :         136 : access_operation::maybe_get_invalid_before_bits (access_range *out) const
     590                 :             : {
     591                 :         136 :   access_range valid_bits (get_valid_bits ());
     592                 :         136 :   access_range actual_bits (get_actual_bits ());
     593                 :             : 
     594                 :         136 :   if (actual_bits.m_start >= valid_bits.m_start)
     595                 :             :     {
     596                 :             :       /* No part of accessed range is before the valid range.  */
     597                 :             :       return false;
     598                 :             :     }
     599                 :          14 :   else if (actual_bits.m_next > valid_bits.m_start)
     600                 :             :     {
     601                 :             :       /* Get part of accessed range that's before the valid range.  */
     602                 :           8 :       *out = access_range (actual_bits.m_start, valid_bits.m_start,
     603                 :           8 :                            *get_manager ());
     604                 :           8 :       return true;
     605                 :             :     }
     606                 :             :   else
     607                 :             :     {
     608                 :             :       /* Accessed range is fully before valid range.  */
     609                 :           6 :       *out = actual_bits;
     610                 :           6 :       return true;
     611                 :             :     }
     612                 :             : }
     613                 :             : 
     614                 :             : /* If there are any bits accessed invalidly after the valid range,
     615                 :             :    return true and write their range to *OUT.
     616                 :             :    Return false if there aren't, or if there's a problem.  */
     617                 :             : 
     618                 :             : bool
     619                 :         136 : access_operation::maybe_get_invalid_after_bits (access_range *out) const
     620                 :             : {
     621                 :         136 :   access_range valid_bits (get_valid_bits ());
     622                 :         136 :   access_range actual_bits (get_actual_bits ());
     623                 :             : 
     624                 :         136 :   if (actual_bits.m_next <= valid_bits.m_next)
     625                 :             :     {
     626                 :             :       /* No part of accessed range is after the valid range.  */
     627                 :             :       return false;
     628                 :             :     }
     629                 :         130 :   else if (actual_bits.m_start < valid_bits.m_next)
     630                 :             :     {
     631                 :             :       /* Get part of accessed range that's after the valid range.  */
     632                 :          62 :       *out = access_range (valid_bits.m_next, actual_bits.m_next,
     633                 :          62 :                            *get_manager ());
     634                 :          62 :       return true;
     635                 :             :     }
     636                 :             :   else
     637                 :             :     {
     638                 :             :       /* Accessed range is fully after valid range.  */
     639                 :          68 :       *out = actual_bits;
     640                 :          68 :       return true;
     641                 :             :     }
     642                 :             : }
     643                 :             : 
     644                 :             : /* A class for capturing all of the region offsets of interest (both concrete
     645                 :             :    and symbolic), to help align everything in the diagram.
     646                 :             :    Boundaries can be soft or hard; hard boundaries are emphasized visually
     647                 :             :    (e.g. the boundary between valid vs invalid accesses).
     648                 :             : 
     649                 :             :    Offsets in the boundaries are all expressed relative to the base
     650                 :             :    region of the access_operation.  */
     651                 :             : 
     652                 :             : class boundaries
     653                 :             : {
     654                 :             : public:
     655                 :             :   enum class kind { HARD, SOFT};
     656                 :             : 
     657                 :          73 :   boundaries (const region &base_reg, logger *logger)
     658                 :          73 :   : m_base_reg (base_reg), m_logger (logger)
     659                 :             :   {
     660                 :             :   }
     661                 :             : 
     662                 :         970 :   void add (region_offset offset, enum kind k)
     663                 :             :   {
     664                 :         364 :     m_all_offsets.insert (offset);
     665                 :         606 :     if (k == kind::HARD)
     666                 :         408 :       m_hard_offsets.insert (offset);
     667                 :             :   }
     668                 :             : 
     669                 :         303 :   void add (const access_range &range, enum kind kind)
     670                 :             :   {
     671                 :         303 :     add (range.m_start, kind);
     672                 :         303 :     add (range.m_next, kind);
     673                 :         303 :     if (m_logger)
     674                 :             :       {
     675                 :           0 :         m_logger->start_log_line ();
     676                 :           0 :         m_logger->log_partial ("added access_range: ");
     677                 :           0 :         range.dump_to_pp (m_logger->get_printer (), true);
     678                 :           0 :         m_logger->log_partial (" (%s)",
     679                 :             :                                (kind == boundaries::kind::HARD)
     680                 :             :                                ? "HARD" : "soft");
     681                 :           0 :         m_logger->end_log_line ();
     682                 :             :       }
     683                 :         303 :   }
     684                 :             : 
     685                 :          84 :   void add (const region &reg, region_model_manager *mgr, enum kind kind)
     686                 :             :   {
     687                 :          84 :     add (access_range (reg.get_offset (mgr),
     688                 :             :                        reg.get_next_offset (mgr),
     689                 :             :                        *mgr),
     690                 :             :          kind);
     691                 :          84 :   }
     692                 :             : 
     693                 :             :   void add (const byte_range bytes, enum kind kind)
     694                 :             :   {
     695                 :             :     add (access_range (&m_base_reg, bytes), kind);
     696                 :             :   }
     697                 :             : 
     698                 :          48 :   void add_all_bytes_in_range (const byte_range &bytes)
     699                 :             :   {
     700                 :          48 :     for (byte_offset_t byte_idx = bytes.get_start_byte_offset ();
     701                 :         412 :          byte_idx <= bytes.get_next_byte_offset ();
     702                 :         364 :          byte_idx = byte_idx + 1)
     703                 :         364 :       add (region_offset::make_concrete (&m_base_reg, byte_idx * 8),
     704                 :             :            kind::SOFT);
     705                 :          48 :   }
     706                 :             : 
     707                 :          20 :   void add_all_bytes_in_range (const access_range &range)
     708                 :             :   {
     709                 :          20 :     byte_range bytes (0, 0);
     710                 :          20 :     bool valid = range.as_concrete_byte_range (&bytes);
     711                 :          20 :     gcc_assert (valid);
     712                 :          20 :     add_all_bytes_in_range (bytes);
     713                 :          20 :   }
     714                 :             : 
     715                 :           0 :   void log (logger &logger) const
     716                 :             :   {
     717                 :           0 :     logger.log ("boundaries:");
     718                 :           0 :     logger.inc_indent ();
     719                 :           0 :     for (auto offset : m_all_offsets)
     720                 :             :       {
     721                 :           0 :         enum kind k = get_kind (offset);
     722                 :           0 :         logger.start_log_line ();
     723                 :           0 :         logger.log_partial ("%s: ", (k == kind::HARD) ? "HARD" : "soft");
     724                 :           0 :         offset.dump_to_pp (logger.get_printer (), true);
     725                 :           0 :         logger.end_log_line ();
     726                 :             :       }
     727                 :           0 :     logger.dec_indent ();
     728                 :           0 :   }
     729                 :             : 
     730                 :         434 :   enum kind get_kind (region_offset offset) const
     731                 :             :   {
     732                 :         434 :     gcc_assert (m_all_offsets.find (offset) != m_all_offsets.end ());
     733                 :         434 :     if (m_hard_offsets.find (offset) != m_hard_offsets.end ())
     734                 :             :       return kind::HARD;
     735                 :             :     else
     736                 :         322 :       return kind::SOFT;
     737                 :             :   }
     738                 :             : 
     739                 :          73 :   std::set<region_offset>::const_iterator begin () const
     740                 :             :   {
     741                 :          73 :     return m_all_offsets.begin ();
     742                 :             :   }
     743                 :          73 :   std::set<region_offset>::const_iterator end () const
     744                 :             :   {
     745                 :          73 :     return m_all_offsets.end ();
     746                 :             :   }
     747                 :             :   std::set<region_offset>::size_type size () const
     748                 :             :   {
     749                 :             :     return m_all_offsets.size ();
     750                 :             :   }
     751                 :             : 
     752                 :             :   std::vector<region_offset>
     753                 :          23 :   get_hard_boundaries_in_range (byte_offset_t min_offset,
     754                 :             :                                 byte_offset_t max_offset) const
     755                 :             :   {
     756                 :          23 :     std::vector<region_offset> result;
     757                 :         109 :     for (auto &offset : m_hard_offsets)
     758                 :             :       {
     759                 :          86 :         if (!offset.concrete_p ())
     760                 :          50 :           continue;
     761                 :          86 :         byte_offset_t byte;
     762                 :          86 :         if (!offset.get_concrete_byte_offset (&byte))
     763                 :           0 :           continue;
     764                 :          86 :         if (byte < min_offset)
     765                 :           4 :           continue;
     766                 :          82 :         if (byte > max_offset)
     767                 :          46 :           continue;
     768                 :          36 :         result.push_back (offset);
     769                 :             :       }
     770                 :          23 :     return result;
     771                 :             :   }
     772                 :             : 
     773                 :             : private:
     774                 :             :   const region &m_base_reg;
     775                 :             :   logger *m_logger;
     776                 :             :   std::set<region_offset> m_all_offsets;
     777                 :             :   std::set<region_offset> m_hard_offsets;
     778                 :             : };
     779                 :             : 
     780                 :             : /* A widget that wraps a table but offloads column-width calculation
     781                 :             :    to a shared object, so that we can vertically line up multiple tables
     782                 :             :    and have them all align their columns.
     783                 :             : 
     784                 :             :    For example, in:
     785                 :             : 
     786                 :             :    01| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     787                 :             :    02| |[0]|[1]|[2]|[3]|[4]|[5]|   ...    |[440]|[441]|[442]|[443]|[444]|[445]|
     788                 :             :    03| +---+---+---+---+---+---+          +-----+-----+-----+-----+-----+-----+
     789                 :             :    04| |'L'|'o'|'r'|'e'|'m'|' '|          | 'o' | 'r' | 'u' | 'm' | '.' | NUL |
     790                 :             :    05| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     791                 :             :    06| |                  string literal (type: 'char[446]')                  |
     792                 :             :    07| +----------------------------------------------------------------------+
     793                 :             :    08|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     794                 :             :    09|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     795                 :             :    10|   v   v   v   v   v   v  v  v    v    v     v     v     v     v     v
     796                 :             :    11|+---+---------------------+----++--------------------------------------+
     797                 :             :    12||[0]|         ...         |[99]||          after valid range           |
     798                 :             :    13|+---+---------------------+----+|                                      |
     799                 :             :    14||  'buf' (type: 'char[100]')   ||                                      |
     800                 :             :    15|+------------------------------++--------------------------------------+
     801                 :             :    16||~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~||~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~|
     802                 :             :    17|               |                                   |
     803                 :             :    18|     +---------+---------+              +----------+----------+
     804                 :             :    19|     |capacity: 100 bytes|              |overflow of 346 bytes|
     805                 :             :    20|     +-------------------+              +---------------------+
     806                 :             : 
     807                 :             :    rows 01-07 and rows 11-15 are x_aligned_table_widget instances.  */
     808                 :             : 
     809                 :             : class x_aligned_table_widget : public leaf_widget
     810                 :             : {
     811                 :             : public:
     812                 :         137 :   x_aligned_table_widget (table t,
     813                 :             :                           const theme &theme,
     814                 :             :                           table_dimension_sizes &col_widths)
     815                 :         137 :   : m_table (std::move (t)),
     816                 :         137 :     m_theme (theme),
     817                 :         137 :     m_col_widths (col_widths),
     818                 :         137 :     m_row_heights (t.get_size ().h),
     819                 :         137 :     m_cell_sizes (m_col_widths, m_row_heights),
     820                 :         274 :     m_tg (m_table, m_cell_sizes)
     821                 :             :   {
     822                 :         137 :   }
     823                 :             : 
     824                 :           0 :   const char *get_desc () const override
     825                 :             :   {
     826                 :           0 :     return "x_aligned_table_widget";
     827                 :             :   }
     828                 :             : 
     829                 :         137 :   canvas::size_t calc_req_size () final override
     830                 :             :   {
     831                 :             :     /* We don't compute the size requirements;
     832                 :             :        the parent should have done this.  */
     833                 :         137 :     return m_tg.get_canvas_size ();
     834                 :             :   }
     835                 :             : 
     836                 :         137 :   void paint_to_canvas (canvas &canvas) final override
     837                 :             :   {
     838                 :         137 :     m_table.paint_to_canvas (canvas,
     839                 :         137 :                              get_top_left (),
     840                 :         137 :                              m_tg,
     841                 :             :                              m_theme);
     842                 :         137 :   }
     843                 :             : 
     844                 :         274 :   const table &get_table () const { return m_table; }
     845                 :         274 :   table_cell_sizes &get_cell_sizes () { return m_cell_sizes; }
     846                 :         137 :   void recalc_coords ()
     847                 :             :   {
     848                 :         137 :     m_tg.recalc_coords ();
     849                 :             :   }
     850                 :             : 
     851                 :             : private:
     852                 :             :   table m_table;
     853                 :             :   const theme &m_theme;
     854                 :             :   table_dimension_sizes &m_col_widths; // Reference to shared column widths
     855                 :             :   table_dimension_sizes m_row_heights; // Unique row heights
     856                 :             :   table_cell_sizes m_cell_sizes;
     857                 :             :   table_geometry m_tg;
     858                 :             : };
     859                 :             : 
     860                 :             : /* A widget for printing arrows between the accessed region
     861                 :             :    and the svalue, showing the direction of the access.
     862                 :             : 
     863                 :             :    For example, in:
     864                 :             : 
     865                 :             :    01| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     866                 :             :    02| |[0]|[1]|[2]|[3]|[4]|[5]|   ...    |[440]|[441]|[442]|[443]|[444]|[445]|
     867                 :             :    03| +---+---+---+---+---+---+          +-----+-----+-----+-----+-----+-----+
     868                 :             :    04| |'L'|'o'|'r'|'e'|'m'|' '|          | 'o' | 'r' | 'u' | 'm' | '.' | NUL |
     869                 :             :    05| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     870                 :             :    06| |                  string literal (type: 'char[446]')                  |
     871                 :             :    07| +----------------------------------------------------------------------+
     872                 :             :    08|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     873                 :             :    09|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     874                 :             :    10|   v   v   v   v   v   v  v  v    v    v     v     v     v     v     v
     875                 :             :    11|+---+---------------------+----++--------------------------------------+
     876                 :             :    12||[0]|         ...         |[99]||          after valid range           |
     877                 :             :    13|+---+---------------------+----+|                                      |
     878                 :             :    14||  'buf' (type: 'char[100]')   ||                                      |
     879                 :             :    15|+------------------------------++--------------------------------------+
     880                 :             :    16||~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~||~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~|
     881                 :             :    17|               |                                   |
     882                 :             :    18|     +---------+---------+              +----------+----------+
     883                 :             :    19|     |capacity: 100 bytes|              |overflow of 346 bytes|
     884                 :             :    20|     +-------------------+              +---------------------+
     885                 :             : 
     886                 :             :    rows 8-10 are the direction widget.  */
     887                 :             : 
     888                 :             : class direction_widget : public leaf_widget
     889                 :             : {
     890                 :             : public:
     891                 :          68 :   direction_widget (const access_diagram_impl &dia_impl,
     892                 :             :                     const bit_to_table_map &btm)
     893                 :          68 :   : leaf_widget (),
     894                 :          68 :     m_dia_impl (dia_impl),
     895                 :          68 :     m_btm (btm)
     896                 :             :   {
     897                 :             :   }
     898                 :           0 :   const char *get_desc () const override
     899                 :             :   {
     900                 :           0 :     return "direction_widget";
     901                 :             :   }
     902                 :          68 :   canvas::size_t calc_req_size () final override
     903                 :             :   {
     904                 :             :     /* Get our width from our siblings.  */
     905                 :          68 :     return canvas::size_t (0, 3);
     906                 :             :   }
     907                 :             :   void paint_to_canvas (canvas &canvas) final override;
     908                 :             : 
     909                 :             : private:
     910                 :             :   const access_diagram_impl &m_dia_impl;
     911                 :             :   const bit_to_table_map &m_btm;
     912                 :             : };
     913                 :             : 
     914                 :             : /* A widget for adding an x_ruler to a diagram based on table columns,
     915                 :             :    offloading column-width calculation to shared objects, so that the ruler
     916                 :             :    lines up with other tables in the diagram.
     917                 :             : 
     918                 :             :    For example, in:
     919                 :             : 
     920                 :             :    01| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     921                 :             :    02| |[0]|[1]|[2]|[3]|[4]|[5]|   ...    |[440]|[441]|[442]|[443]|[444]|[445]|
     922                 :             :    03| +---+---+---+---+---+---+          +-----+-----+-----+-----+-----+-----+
     923                 :             :    04| |'L'|'o'|'r'|'e'|'m'|' '|          | 'o' | 'r' | 'u' | 'm' | '.' | NUL |
     924                 :             :    05| +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
     925                 :             :    06| |                  string literal (type: 'char[446]')                  |
     926                 :             :    07| +----------------------------------------------------------------------+
     927                 :             :    08|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     928                 :             :    09|   |   |   |   |   |   |  |  |    |    |     |     |     |     |     |
     929                 :             :    10|   v   v   v   v   v   v  v  v    v    v     v     v     v     v     v
     930                 :             :    11|+---+---------------------+----++--------------------------------------+
     931                 :             :    12||[0]|         ...         |[99]||          after valid range           |
     932                 :             :    13|+---+---------------------+----+|                                      |
     933                 :             :    14||  'buf' (type: 'char[100]')   ||                                      |
     934                 :             :    15|+------------------------------++--------------------------------------+
     935                 :             :    16||~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~||~~~~~~~~~~~~~~~~~~+~~~~~~~~~~~~~~~~~~~|
     936                 :             :    17|               |                                   |
     937                 :             :    18|     +---------+---------+              +----------+----------+
     938                 :             :    19|     |capacity: 100 bytes|              |overflow of 346 bytes|
     939                 :             :    20|     +-------------------+              +---------------------+
     940                 :             : 
     941                 :             :    rows 16-20 are the x_aligned_x_ruler_widget.  */
     942                 :             : 
     943                 :             : class x_aligned_x_ruler_widget : public leaf_widget
     944                 :             : {
     945                 :             : public:
     946                 :          68 :   x_aligned_x_ruler_widget (const access_diagram_impl &dia_impl,
     947                 :             :                             const theme &theme)
     948                 :          68 :   : m_dia_impl (dia_impl),
     949                 :          68 :     m_theme (theme)
     950                 :             :   {
     951                 :             :   }
     952                 :             : 
     953                 :           0 :   const char *get_desc () const override
     954                 :             :   {
     955                 :           0 :     return "x_aligned_ruler_widget";
     956                 :             :   }
     957                 :             : 
     958                 :         156 :   void add_range (const table::range_t &x_range,
     959                 :             :                   styled_string text,
     960                 :             :                   style::id_t style_id)
     961                 :             :   {
     962                 :         156 :     m_labels.push_back (label (x_range, std::move (text), style_id));
     963                 :         156 :   }
     964                 :             : 
     965                 :          68 :   canvas::size_t calc_req_size () final override
     966                 :             :   {
     967                 :          68 :     x_ruler r (make_x_ruler ());
     968                 :          68 :     return r.get_size ();
     969                 :          68 :   }
     970                 :             : 
     971                 :          68 :   void paint_to_canvas (canvas &canvas) final override
     972                 :             :   {
     973                 :          68 :     x_ruler r (make_x_ruler ());
     974                 :          68 :     r.paint_to_canvas (canvas,
     975                 :          68 :                        get_top_left (),
     976                 :             :                        m_theme);
     977                 :          68 :   }
     978                 :             : 
     979                 :             : private:
     980                 :         577 :   struct label
     981                 :             :   {
     982                 :         156 :     label (const table::range_t &table_x_range,
     983                 :             :            styled_string text,
     984                 :             :            style::id_t style_id)
     985                 :         156 :     : m_table_x_range (table_x_range),
     986                 :         156 :       m_text (std::move (text)),
     987                 :         156 :       m_style_id (style_id)
     988                 :             :     {
     989                 :             :     }
     990                 :             :     table::range_t m_table_x_range;
     991                 :             :     styled_string m_text;
     992                 :             :     style::id_t m_style_id;
     993                 :             :   };
     994                 :             : 
     995                 :             :   x_ruler make_x_ruler () const;
     996                 :             : 
     997                 :             :   const access_diagram_impl &m_dia_impl;
     998                 :             :   const theme &m_theme;
     999                 :             :   std::vector<label> m_labels;
    1000                 :             : };
    1001                 :             : 
    1002                 :             : /* A two-way mapping between access_ranges and table columns, for use by
    1003                 :             :    spatial_item subclasses for creating tables.
    1004                 :             :    For example when visualizing a bogus access of 'int arr[10];'
    1005                 :             :    at 'arr[10]', we might have:
    1006                 :             :    - table column 0 is "bytes 0-3" (for arr[0])
    1007                 :             :    - table column 1 is "bytes 4-35" (for arr[1] through arr[8])
    1008                 :             :    - table column 2 is "bytes 36-39 (for arr[9])
    1009                 :             :    - table column 3 is blank to emphasize a hard boundary between
    1010                 :             :      valid/invalid accesses.
    1011                 :             :    - table column 4 is "bytes 40-44" (for arr[10])
    1012                 :             : 
    1013                 :             :    We store this as a pair of maps from region_offset to table x; in
    1014                 :             :    the abvove example:
    1015                 :             : 
    1016                 :             :      region offset          table_x  prev_table_x
    1017                 :             :      bit 0 (aka byte 0)     0        (none)
    1018                 :             :      bit 32 (aka byte 4)    1        0
    1019                 :             :      bit 288 (aka byte 36)  2        1
    1020                 :             :      bit 320 (aka byte 40)  4        2
    1021                 :             :      bit 352 (aka byte 44)  (none)   (none)
    1022                 :             : 
    1023                 :             :      so that e.g given the half-open byte range [0, 40)
    1024                 :             :      we can determine the closed range of table x [0, 2].  */
    1025                 :             : 
    1026                 :          73 : class bit_to_table_map
    1027                 :             : {
    1028                 :             : public:
    1029                 :             :   /* Populate m_table_x_for_bit and m_bit_for_table_x.  */
    1030                 :          73 :   void populate (const boundaries &boundaries,
    1031                 :             :                  region_model_manager &mgr,
    1032                 :             :                  logger *logger)
    1033                 :             :   {
    1034                 :          73 :     LOG_SCOPE (logger);
    1035                 :             : 
    1036                 :          73 :     int table_x = 0;
    1037                 :          73 :     std::vector <region_offset> vec_boundaries (boundaries.begin (),
    1038                 :          73 :                                                 boundaries.end ());
    1039                 :             : 
    1040                 :             :     /* Sort into an order that makes sense.  */
    1041                 :          73 :     std::sort (vec_boundaries.begin (),
    1042                 :             :                vec_boundaries.end ());
    1043                 :             : 
    1044                 :          73 :     if (logger)
    1045                 :             :       {
    1046                 :           0 :         logger->log ("vec_boundaries");
    1047                 :           0 :         logger->inc_indent ();
    1048                 :           0 :         for (unsigned idx = 0; idx < vec_boundaries.size (); idx++)
    1049                 :             :           {
    1050                 :           0 :             logger->start_log_line ();
    1051                 :           0 :             logger->log_partial ("idx: %i: ", idx);
    1052                 :           0 :             vec_boundaries[idx].dump_to_pp (logger->get_printer (), true);
    1053                 :           0 :             logger->end_log_line ();
    1054                 :             :           }
    1055                 :           0 :         logger->dec_indent ();
    1056                 :             :       }
    1057                 :             : 
    1058                 :         653 :     for (size_t idx = 0; idx < vec_boundaries.size (); idx++)
    1059                 :             :       {
    1060                 :         580 :         const region_offset &offset = vec_boundaries[idx];
    1061                 :         580 :         if (idx > 0 && (idx + 1) < vec_boundaries.size ())
    1062                 :             :           {
    1063                 :         434 :             if (boundaries.get_kind (offset) == boundaries::kind::HARD)
    1064                 :         112 :               table_x += 1;
    1065                 :             :           }
    1066                 :         580 :         m_table_x_for_offset[offset] = table_x;
    1067                 :         580 :         if ((idx + 1) < vec_boundaries.size ())
    1068                 :             :           {
    1069                 :         507 :             const region_offset &next_offset = vec_boundaries[idx + 1];
    1070                 :         507 :             m_table_x_for_prev_offset[next_offset] = table_x;
    1071                 :         507 :             m_range_for_table_x[table_x]
    1072                 :        1014 :               = access_range (offset, next_offset, mgr);
    1073                 :             :           }
    1074                 :         580 :         table_x += 1;
    1075                 :             :       }
    1076                 :          73 :     m_num_columns = table_x - 1;
    1077                 :             : 
    1078                 :          73 :     if (logger)
    1079                 :           0 :       log (*logger);
    1080                 :          73 :   }
    1081                 :             : 
    1082                 :        1775 :   unsigned get_num_columns () const
    1083                 :             :   {
    1084                 :        1775 :     return m_num_columns;
    1085                 :             :   }
    1086                 :             : 
    1087                 :        1170 :   table::range_t get_table_x_for_range (const access_range &range) const
    1088                 :             :   {
    1089                 :        1170 :     return table::range_t (get_table_x_for_offset (range.m_start),
    1090                 :        1170 :                            get_table_x_for_prev_offset (range.m_next) + 1);
    1091                 :             :   }
    1092                 :             : 
    1093                 :         789 :   table::rect_t get_table_rect (const access_range &range,
    1094                 :             :                                 const int table_y, const int table_h) const
    1095                 :             :   {
    1096                 :         789 :     const table::range_t x_range (get_table_x_for_range (range));
    1097                 :         789 :     return table::rect_t (table::coord_t (x_range.start, table_y),
    1098                 :         789 :                           table::size_t (x_range.get_size (), table_h));
    1099                 :             :   }
    1100                 :             : 
    1101                 :         600 :   table::rect_t get_table_rect (const region *base_reg,
    1102                 :             :                                 const bit_range &bits,
    1103                 :             :                                 const int table_y, const int table_h) const
    1104                 :             :   {
    1105                 :         600 :     const access_range range (base_reg, bits);
    1106                 :         600 :     return get_table_rect (range, table_y, table_h);
    1107                 :             :   }
    1108                 :             : 
    1109                 :         600 :   table::rect_t get_table_rect (const region *base_reg,
    1110                 :             :                                 const byte_range &bytes,
    1111                 :             :                                 const int table_y, const int table_h) const
    1112                 :             :   {
    1113                 :         600 :     return get_table_rect (base_reg, bytes.as_bit_range (), table_y, table_h);
    1114                 :             :   }
    1115                 :             : 
    1116                 :        1213 :   bool maybe_get_access_range_for_table_x (int table_x,
    1117                 :             :                                            access_range *out) const
    1118                 :             :   {
    1119                 :        1213 :     auto slot = m_range_for_table_x.find (table_x);
    1120                 :        1213 :     if (slot == m_range_for_table_x.end ())
    1121                 :             :       return false;
    1122                 :         998 :     *out = slot->second;
    1123                 :         998 :     return true;
    1124                 :             :   }
    1125                 :             : 
    1126                 :           0 :   void log (logger &logger) const
    1127                 :             :   {
    1128                 :           0 :     logger.log ("table columns");
    1129                 :           0 :     logger.inc_indent ();
    1130                 :           0 :     for (unsigned table_x = 0; table_x < get_num_columns (); table_x++)
    1131                 :             :       {
    1132                 :           0 :         logger.start_log_line ();
    1133                 :           0 :         logger.log_partial ("table_x: %i", table_x);
    1134                 :           0 :         access_range range_for_column (NULL, bit_range (0, 0));
    1135                 :           0 :         if (maybe_get_access_range_for_table_x (table_x, &range_for_column))
    1136                 :             :           {
    1137                 :           0 :             logger.log_partial (": range: ");
    1138                 :           0 :             range_for_column.dump_to_pp (logger.get_printer (), true);
    1139                 :             :           }
    1140                 :           0 :         logger.end_log_line ();
    1141                 :             :       }
    1142                 :           0 :     logger.dec_indent ();
    1143                 :           0 :   }
    1144                 :             : 
    1145                 :        1206 :   int get_table_x_for_offset (region_offset offset) const
    1146                 :             :   {
    1147                 :        1206 :     auto slot = m_table_x_for_offset.find (offset);
    1148                 :             : 
    1149                 :             :     /* If this fails, then we probably failed to fully populate m_boundaries
    1150                 :             :        in find_boundaries.  */
    1151                 :        1206 :     gcc_assert (slot != m_table_x_for_offset.end ());
    1152                 :             : 
    1153                 :        1206 :     return slot->second;
    1154                 :             :   }
    1155                 :             : 
    1156                 :             : private:
    1157                 :        1170 :   int get_table_x_for_prev_offset (region_offset offset) const
    1158                 :             :   {
    1159                 :        1170 :     auto slot = m_table_x_for_prev_offset.find (offset);
    1160                 :             : 
    1161                 :             :     /* If this fails, then we probably failed to fully populate m_boundaries
    1162                 :             :        in find_boundaries.  */
    1163                 :        1170 :     gcc_assert (slot != m_table_x_for_prev_offset.end ());
    1164                 :             : 
    1165                 :        1170 :     return slot->second;
    1166                 :             :   }
    1167                 :             : 
    1168                 :             :   std::map<region_offset, int> m_table_x_for_offset;
    1169                 :             :   std::map<region_offset, int> m_table_x_for_prev_offset;
    1170                 :             :   std::map<int, access_range> m_range_for_table_x;
    1171                 :             :   unsigned m_num_columns;
    1172                 :             : };
    1173                 :             : 
    1174                 :             : /* Base class for something in the diagram that participates
    1175                 :             :    in two steps of diagram creation:
    1176                 :             :    (a) populating a boundaries instance with the boundaries of interest
    1177                 :             :    (b) creating a table instance for itself.
    1178                 :             : 
    1179                 :             :    Offsets in the boundaries are all expressed relative to the base
    1180                 :             :    region of the access_operation.  */
    1181                 :             : 
    1182                 :         232 : class spatial_item
    1183                 :             : {
    1184                 :             : public:
    1185                 :             :   virtual ~spatial_item () {}
    1186                 :             :   virtual void add_boundaries (boundaries &out, logger *) const = 0;
    1187                 :             : 
    1188                 :             :   virtual table make_table (const bit_to_table_map &btm,
    1189                 :             :                             style_manager &sm) const = 0;
    1190                 :             : };
    1191                 :             : 
    1192                 :             : /* A spatial_item that involves showing an svalue at a particular offset.  */
    1193                 :             : 
    1194                 :             : class svalue_spatial_item : public spatial_item
    1195                 :             : {
    1196                 :             : public:
    1197                 :             :   enum class kind
    1198                 :             :   {
    1199                 :             :      WRITTEN,
    1200                 :             :      EXISTING
    1201                 :             :   };
    1202                 :             : protected:
    1203                 :          47 :   svalue_spatial_item (const svalue &sval,
    1204                 :             :                        access_range bits,
    1205                 :             :                        enum kind kind)
    1206                 :          47 :   : m_sval (sval), m_bits (bits), m_kind (kind)
    1207                 :             :   {
    1208                 :             :   }
    1209                 :             : 
    1210                 :             :   const svalue &m_sval;
    1211                 :             :   access_range m_bits;
    1212                 :             :   enum kind m_kind;
    1213                 :             : };
    1214                 :             : 
    1215                 :             : static std::unique_ptr<spatial_item>
    1216                 :             : make_existing_svalue_spatial_item (const svalue *sval,
    1217                 :             :                                    const access_range &bits,
    1218                 :             :                                    const theme &theme);
    1219                 :             : 
    1220                 :             : class compound_svalue_spatial_item : public svalue_spatial_item
    1221                 :             : {
    1222                 :             : public:
    1223                 :          13 :   compound_svalue_spatial_item (const compound_svalue &sval,
    1224                 :             :                                 const access_range &bits,
    1225                 :             :                                 enum kind kind,
    1226                 :             :                                 const theme &theme)
    1227                 :          13 :   : svalue_spatial_item (sval, bits, kind),
    1228                 :          13 :     m_compound_sval (sval)
    1229                 :             :   {
    1230                 :          13 :     const binding_map &map = m_compound_sval.get_map ();
    1231                 :          13 :     auto_vec <const binding_key *> binding_keys;
    1232                 :          88 :     for (auto iter : map)
    1233                 :             :       {
    1234                 :          31 :         const binding_key *key = iter.first;
    1235                 :          31 :         const svalue *bound_sval = iter.second;
    1236                 :          62 :         if (const concrete_binding *concrete_key
    1237                 :          31 :               = key->dyn_cast_concrete_binding ())
    1238                 :             :           {
    1239                 :          31 :             access_range range (nullptr,
    1240                 :          31 :                                 concrete_key->get_bit_range ());
    1241                 :          31 :             if (std::unique_ptr<spatial_item> child
    1242                 :             :                   = make_existing_svalue_spatial_item (bound_sval,
    1243                 :             :                                                        range,
    1244                 :          31 :                                                        theme))
    1245                 :          31 :               m_children.push_back (std::move (child));
    1246                 :             :           }
    1247                 :             :       }
    1248                 :          13 :   }
    1249                 :             : 
    1250                 :          13 :   void add_boundaries (boundaries &out, logger *logger) const final override
    1251                 :             :   {
    1252                 :          13 :     LOG_SCOPE (logger);
    1253                 :          26 :     for (auto &iter : m_children)
    1254                 :          13 :       iter->add_boundaries (out, logger);
    1255                 :          13 :   }
    1256                 :             : 
    1257                 :          13 :   table make_table (const bit_to_table_map &btm,
    1258                 :             :                     style_manager &sm) const final override
    1259                 :             :   {
    1260                 :          13 :     std::vector<table> child_tables;
    1261                 :          13 :     int max_rows = 0;
    1262                 :          26 :     for (auto &iter : m_children)
    1263                 :             :       {
    1264                 :          13 :         table child_table (iter->make_table (btm, sm));
    1265                 :          13 :         max_rows = MAX (max_rows, child_table.get_size ().h);
    1266                 :          13 :         child_tables.push_back (std::move (child_table));
    1267                 :          13 :       }
    1268                 :          13 :     table t (table::size_t (btm.get_num_columns (), max_rows));
    1269                 :          26 :     for (auto &&child_table : child_tables)
    1270                 :          13 :       t.add_other_table (std::move (child_table),
    1271                 :             :                          table::coord_t (0, 0));
    1272                 :          26 :     return t;
    1273                 :          13 :   }
    1274                 :             : 
    1275                 :             : private:
    1276                 :             :   const compound_svalue &m_compound_sval;
    1277                 :             :   std::vector<std::unique_ptr<spatial_item>> m_children;
    1278                 :             : };
    1279                 :             : 
    1280                 :             : /* Loop through the TABLE_X_RANGE columns of T, adding
    1281                 :             :    cells containing "..." in any unoccupied ranges of table cell.  */
    1282                 :             : 
    1283                 :             : static void
    1284                 :          42 : add_ellipsis_to_gaps (table &t,
    1285                 :             :                       style_manager &sm,
    1286                 :             :                       const table::range_t &table_x_range,
    1287                 :             :                       const table::range_t &table_y_range)
    1288                 :             : {
    1289                 :          42 :   int table_x = table_x_range.get_min ();
    1290                 :          89 :   while (table_x < table_x_range.get_next ())
    1291                 :             :     {
    1292                 :             :       /* Find a run of unoccupied table cells.  */
    1293                 :             :       const int start_table_x = table_x;
    1294                 :         267 :       while (table_x < table_x_range.get_next ()
    1295                 :         267 :              && !t.get_placement_at (table::coord_t (table_x,
    1296                 :             :                                                      table_y_range.get_min ())))
    1297                 :         220 :         table_x++;
    1298                 :          47 :       const table::range_t unoccupied_x_range (start_table_x, table_x);
    1299                 :          47 :       if (unoccupied_x_range.get_size () > 0)
    1300                 :          47 :         t.set_cell_span (table::rect_t (unoccupied_x_range, table_y_range),
    1301                 :          94 :                          styled_string (sm, "..."));
    1302                 :             :       /* Skip occupied table cells.  */
    1303                 :          60 :       while (table_x < table_x_range.get_next ()
    1304                 :          60 :              && t.get_placement_at (table::coord_t (table_x,
    1305                 :             :                                                     table_y_range.get_min ())))
    1306                 :          13 :         table_x++;
    1307                 :             :     }
    1308                 :          42 : }
    1309                 :             : 
    1310                 :             : /* Subclass of spatial_item for visualizing the region of memory
    1311                 :             :    that's valid to access relative to the base region of region accessed in
    1312                 :             :    the operation.  */
    1313                 :             : 
    1314                 :             : class valid_region_spatial_item : public spatial_item
    1315                 :             : {
    1316                 :             : public:
    1317                 :          73 :   valid_region_spatial_item (const access_operation &op,
    1318                 :             :                              diagnostic_event_id_t region_creation_event_id,
    1319                 :             :                              const theme &theme)
    1320                 :          73 :   : m_op (op),
    1321                 :          73 :     m_region_creation_event_id (region_creation_event_id),
    1322                 :          73 :     m_boundaries (nullptr),
    1323                 :         146 :     m_existing_sval (op.m_model.get_store_value (op.m_base_region, nullptr)),
    1324                 :          73 :     m_existing_sval_spatial_item
    1325                 :             :       (make_existing_svalue_spatial_item (m_existing_sval,
    1326                 :          73 :                                           op.get_valid_bits (),
    1327                 :          73 :                                           theme))
    1328                 :             :   {
    1329                 :          73 :   }
    1330                 :             : 
    1331                 :          73 :   void add_boundaries (boundaries &out, logger *logger) const final override
    1332                 :             :   {
    1333                 :          73 :     LOG_SCOPE (logger);
    1334                 :          73 :     m_boundaries = &out;
    1335                 :          73 :     access_range valid_bits = m_op.get_valid_bits ();
    1336                 :          73 :     if (logger)
    1337                 :             :       {
    1338                 :           0 :         logger->start_log_line ();
    1339                 :           0 :         logger->log_partial ("valid bits: ");
    1340                 :           0 :         valid_bits.dump_to_pp (logger->get_printer (), true);
    1341                 :           0 :         logger->end_log_line ();
    1342                 :             :       }
    1343                 :          73 :     out.add (valid_bits, boundaries::kind::HARD);
    1344                 :             : 
    1345                 :          73 :     if (m_existing_sval_spatial_item)
    1346                 :             :       {
    1347                 :          15 :         if (logger)
    1348                 :             :           {
    1349                 :           0 :             logger->start_log_line ();
    1350                 :           0 :             logger->log_partial ("existing svalue: ");
    1351                 :           0 :             m_existing_sval->dump_to_pp (logger->get_printer (), true);
    1352                 :           0 :             logger->end_log_line ();
    1353                 :             :           }
    1354                 :          15 :         m_existing_sval_spatial_item->add_boundaries (out, logger);
    1355                 :             :       }
    1356                 :             : 
    1357                 :             :     /* Support for showing first and final element in array types.  */
    1358                 :          73 :     if (tree base_type = m_op.m_base_region->get_type ())
    1359                 :          43 :       if (TREE_CODE (base_type) == ARRAY_TYPE)
    1360                 :             :         {
    1361                 :          43 :           if (logger)
    1362                 :           0 :             logger->log ("showing first and final element in array type");
    1363                 :          43 :           region_model_manager *mgr = m_op.m_model.get_manager ();
    1364                 :          43 :           tree domain = TYPE_DOMAIN (base_type);
    1365                 :          43 :           if (domain && TYPE_MIN_VALUE (domain) && TYPE_MAX_VALUE (domain))
    1366                 :             :             {
    1367                 :          42 :               const svalue *min_idx_sval
    1368                 :          42 :                 = mgr->get_or_create_constant_svalue (TYPE_MIN_VALUE (domain));
    1369                 :          42 :               const svalue *max_idx_sval
    1370                 :          42 :                 = mgr->get_or_create_constant_svalue (TYPE_MAX_VALUE (domain));
    1371                 :          42 :               const region *min_element =
    1372                 :          42 :                 mgr->get_element_region (m_op.m_base_region,
    1373                 :          42 :                                          TREE_TYPE (base_type),
    1374                 :             :                                          min_idx_sval);
    1375                 :          42 :               out.add (*min_element, mgr, boundaries::kind::SOFT);
    1376                 :          42 :               const region *max_element =
    1377                 :          42 :                 mgr->get_element_region (m_op.m_base_region,
    1378                 :          42 :                                          TREE_TYPE (base_type),
    1379                 :             :                                          max_idx_sval);
    1380                 :          42 :               out.add (*max_element, mgr, boundaries::kind::SOFT);
    1381                 :             :             }
    1382                 :             :         }
    1383                 :          73 :   }
    1384                 :             : 
    1385                 :             :   /* Subroutine of make_table when base region has ARRAY_TYPE.  */
    1386                 :          43 :   void add_array_elements_to_table (table &t,
    1387                 :             :                                     const bit_to_table_map &btm,
    1388                 :             :                                     style_manager &sm) const
    1389                 :             :   {
    1390                 :          43 :     tree base_type = m_op.m_base_region->get_type ();
    1391                 :          43 :     gcc_assert (TREE_CODE (base_type) == ARRAY_TYPE);
    1392                 :          43 :     gcc_assert (m_boundaries != nullptr);
    1393                 :             : 
    1394                 :          43 :     tree domain = TYPE_DOMAIN (base_type);
    1395                 :          43 :     if (!(domain && TYPE_MIN_VALUE (domain) && TYPE_MAX_VALUE (domain)))
    1396                 :           1 :       return;
    1397                 :             : 
    1398                 :          42 :     const int table_y = 0;
    1399                 :          42 :     const int table_h = 1;
    1400                 :          42 :     const table::range_t table_y_range (table_y, table_y + table_h);
    1401                 :             : 
    1402                 :          42 :     t.add_row ();
    1403                 :             : 
    1404                 :          42 :     const table::range_t min_x_range
    1405                 :          42 :       = maybe_add_array_index_to_table (t, btm, sm, table_y_range,
    1406                 :          42 :                                         TYPE_MIN_VALUE (domain));
    1407                 :          42 :     const table::range_t max_x_range
    1408                 :          42 :       = maybe_add_array_index_to_table (t, btm, sm, table_y_range,
    1409                 :          42 :                                         TYPE_MAX_VALUE (domain));
    1410                 :             : 
    1411                 :          42 :     if (TREE_TYPE (base_type) == char_type_node)
    1412                 :             :       {
    1413                 :             :         /* For a char array,: if there are any hard boundaries in
    1414                 :             :            m_boundaries that are *within* the valid region,
    1415                 :             :            then show those index values.  */
    1416                 :          23 :         std::vector<region_offset> hard_boundaries
    1417                 :          23 :           = m_boundaries->get_hard_boundaries_in_range
    1418                 :          23 :               (tree_to_shwi (TYPE_MIN_VALUE (domain)),
    1419                 :          46 :                tree_to_shwi (TYPE_MAX_VALUE (domain)));
    1420                 :          59 :         for (auto &offset : hard_boundaries)
    1421                 :             :           {
    1422                 :          36 :             const int table_x = btm.get_table_x_for_offset (offset);
    1423                 :          36 :             if (!offset.concrete_p ())
    1424                 :           0 :               continue;
    1425                 :          36 :             byte_offset_t byte;
    1426                 :          36 :             if (!offset.get_concrete_byte_offset (&byte))
    1427                 :           0 :               continue;
    1428                 :          36 :             table::range_t table_x_range (table_x, table_x + 1);
    1429                 :          36 :             t.maybe_set_cell_span (table::rect_t (table_x_range,
    1430                 :             :                                                   table_y_range),
    1431                 :          72 :                                    fmt_styled_string (sm, "[%wi]",
    1432                 :             :                                                       byte.to_shwi ()));
    1433                 :             :           }
    1434                 :          23 :       }
    1435                 :             : 
    1436                 :          42 :     add_ellipsis_to_gaps (t, sm,
    1437                 :          42 :                           table::range_t (min_x_range.get_next (),
    1438                 :             :                                           max_x_range.get_min ()),
    1439                 :             :                           table_y_range);
    1440                 :             :   }
    1441                 :             : 
    1442                 :             :   table::range_t
    1443                 :          84 :   maybe_add_array_index_to_table (table &t,
    1444                 :             :                                   const bit_to_table_map &btm,
    1445                 :             :                                   style_manager &sm,
    1446                 :             :                                   const table::range_t table_y_range,
    1447                 :             :                                   tree idx_cst) const
    1448                 :             :   {
    1449                 :          84 :     region_model_manager * const mgr = m_op.get_manager ();
    1450                 :          84 :     tree base_type = m_op.m_base_region->get_type ();
    1451                 :          84 :     const svalue *idx_sval
    1452                 :          84 :       = mgr->get_or_create_constant_svalue (idx_cst);
    1453                 :          84 :     const region *element_reg = mgr->get_element_region (m_op.m_base_region,
    1454                 :          84 :                                                          TREE_TYPE (base_type),
    1455                 :             :                                                          idx_sval);
    1456                 :          84 :     const access_range element_range (*element_reg, mgr);
    1457                 :          84 :     const table::range_t element_x_range
    1458                 :          84 :       = btm.get_table_x_for_range (element_range);
    1459                 :             : 
    1460                 :          84 :     t.maybe_set_cell_span (table::rect_t (element_x_range,
    1461                 :             :                                           table_y_range),
    1462                 :          84 :                            fmt_styled_string (sm, "[%E]", idx_cst));
    1463                 :             : 
    1464                 :          84 :     return element_x_range;
    1465                 :             :   }
    1466                 :             : 
    1467                 :          68 :   table make_table (const bit_to_table_map &btm,
    1468                 :             :                     style_manager &sm) const final override
    1469                 :             :   {
    1470                 :          68 :     table t (table::size_t (btm.get_num_columns (), 0));
    1471                 :             : 
    1472                 :          68 :     if (tree base_type = m_op.m_base_region->get_type ())
    1473                 :          43 :       if (TREE_CODE (base_type) == ARRAY_TYPE)
    1474                 :          43 :         add_array_elements_to_table (t, btm, sm);
    1475                 :             : 
    1476                 :             :     /* Make use of m_existing_sval_spatial_item, if any.  */
    1477                 :          68 :     if (m_existing_sval_spatial_item)
    1478                 :             :       {
    1479                 :          15 :         table table_for_existing
    1480                 :          15 :           = m_existing_sval_spatial_item->make_table (btm, sm);
    1481                 :          15 :         const int table_y = t.add_rows (table_for_existing.get_size ().h);
    1482                 :          15 :         t.add_other_table (std::move (table_for_existing),
    1483                 :             :                            table::coord_t (0, table_y));
    1484                 :          15 :       }
    1485                 :             : 
    1486                 :          68 :     access_range valid_bits = m_op.get_valid_bits ();
    1487                 :          68 :     const int table_y = t.add_row ();
    1488                 :          68 :     const int table_h = 1;
    1489                 :          68 :     table::rect_t rect = btm.get_table_rect (valid_bits, table_y, table_h);
    1490                 :          68 :     styled_string s;
    1491                 :          68 :     switch (m_op.m_base_region->get_kind ())
    1492                 :             :       {
    1493                 :           0 :       default:
    1494                 :           0 :         s = styled_string (sm, _("region"));
    1495                 :           0 :         break;
    1496                 :          41 :       case RK_DECL:
    1497                 :          41 :         {
    1498                 :          41 :           const decl_region *decl_reg
    1499                 :          41 :             = as_a <const decl_region *> (m_op.m_base_region);
    1500                 :          41 :           tree decl = decl_reg->get_decl ();
    1501                 :          41 :           s = fmt_styled_string (sm, "%qE (type: %qT)",
    1502                 :             :                                  decl,
    1503                 :          82 :                                  TREE_TYPE (decl));
    1504                 :             :         }
    1505                 :          41 :         break;
    1506                 :          11 :       case RK_HEAP_ALLOCATED:
    1507                 :          11 :         {
    1508                 :          11 :           if (m_region_creation_event_id.known_p ())
    1509                 :          22 :             s = fmt_styled_string (sm, _("buffer allocated on heap at %@"),
    1510                 :          11 :                                    &m_region_creation_event_id);
    1511                 :             :           else
    1512                 :           0 :             s = styled_string (sm, _("heap-allocated buffer"));
    1513                 :             :         }
    1514                 :             :         break;
    1515                 :          14 :       case RK_ALLOCA:
    1516                 :          14 :         {
    1517                 :          14 :           if (m_region_creation_event_id.known_p ())
    1518                 :          28 :             s = fmt_styled_string (sm, _("buffer allocated on stack at %@"),
    1519                 :          14 :                                    &m_region_creation_event_id);
    1520                 :             :           else
    1521                 :           0 :             s = styled_string (sm, _("stack-allocated buffer"));
    1522                 :             :         }
    1523                 :             :         break;
    1524                 :           2 :       case RK_STRING:
    1525                 :           2 :         {
    1526                 :           2 :           const string_region *string_reg
    1527                 :           2 :             = as_a <const string_region *> (m_op.m_base_region);
    1528                 :           2 :           tree string_cst = string_reg->get_string_cst ();
    1529                 :           2 :           s = fmt_styled_string (sm, _("string literal (type: %qT)"),
    1530                 :           4 :                                  TREE_TYPE (string_cst));
    1531                 :             :         }
    1532                 :           2 :         break;
    1533                 :             :       }
    1534                 :          68 :     t.set_cell_span (rect, std::move (s));
    1535                 :             : 
    1536                 :          68 :     return t;
    1537                 :          68 :   }
    1538                 :             : 
    1539                 :             : private:
    1540                 :             :   const access_operation &m_op;
    1541                 :             :   diagnostic_event_id_t m_region_creation_event_id;
    1542                 :             :   mutable const boundaries *m_boundaries;
    1543                 :             :   const svalue *m_existing_sval;
    1544                 :             :   std::unique_ptr<spatial_item> m_existing_sval_spatial_item;
    1545                 :             : };
    1546                 :             : 
    1547                 :             : /* Subclass of spatial_item for visualizing the region of memory
    1548                 :             :    that's actually accessed by the read or write, for reads and
    1549                 :             :    for write cases where we don't know the svalue written.  */
    1550                 :             : 
    1551                 :             : class accessed_region_spatial_item : public spatial_item
    1552                 :             : {
    1553                 :             : public:
    1554                 :          73 :   accessed_region_spatial_item (const access_operation &op) : m_op (op) {}
    1555                 :             : 
    1556                 :          73 :   void add_boundaries (boundaries &out, logger *logger) const final override
    1557                 :             :   {
    1558                 :          73 :     LOG_SCOPE (logger);
    1559                 :          73 :     access_range actual_bits = m_op.get_actual_bits ();
    1560                 :          73 :     if (logger)
    1561                 :             :       {
    1562                 :           0 :         logger->start_log_line ();
    1563                 :           0 :         logger->log_partial ("actual bits: ");
    1564                 :           0 :         actual_bits.dump_to_pp (logger->get_printer (), true);
    1565                 :           0 :         logger->end_log_line ();
    1566                 :             :       }
    1567                 :          73 :     out.add (actual_bits, boundaries::kind::HARD);
    1568                 :          73 :   }
    1569                 :             : 
    1570                 :          15 :   table make_table (const bit_to_table_map &btm,
    1571                 :             :                     style_manager &sm) const final override
    1572                 :             :   {
    1573                 :          15 :     table t (table::size_t (btm.get_num_columns (), 1));
    1574                 :             : 
    1575                 :          15 :     access_range actual_bits = m_op.get_actual_bits ();
    1576                 :          15 :     const int table_y = 0;
    1577                 :          15 :     const int table_h = 1;
    1578                 :          15 :     table::rect_t rect = btm.get_table_rect (actual_bits, table_y, table_h);
    1579                 :          15 :     t.set_cell_span (rect, styled_string (get_label_string (sm)));
    1580                 :             : 
    1581                 :          15 :     return t;
    1582                 :             :   }
    1583                 :             : 
    1584                 :             : private:
    1585                 :          15 :   styled_string get_label_string (style_manager &sm) const
    1586                 :             :   {
    1587                 :          15 :     const access_range accessed_bits (m_op.get_actual_bits ());
    1588                 :          15 :     return get_access_size_str (sm,
    1589                 :             :                                 m_op,
    1590                 :             :                                 accessed_bits,
    1591                 :          15 :                                 m_op.m_reg.get_type ());
    1592                 :             :   }
    1593                 :             : 
    1594                 :             :   const access_operation &m_op;
    1595                 :             : };
    1596                 :             : 
    1597                 :             : /* Subclass of spatial_item for when we know the svalue being written
    1598                 :             :    to the accessed region.
    1599                 :             :    Can be subclassed to give visualizations of specific kinds of svalue.  */
    1600                 :             : 
    1601                 :             : class written_svalue_spatial_item : public spatial_item
    1602                 :             : {
    1603                 :             : public:
    1604                 :          39 :   written_svalue_spatial_item (const access_operation &op,
    1605                 :             :                        const svalue &sval,
    1606                 :             :                        access_range actual_bits)
    1607                 :          39 :   : m_op (op), m_sval (sval), m_actual_bits (actual_bits)
    1608                 :             :   {}
    1609                 :             : 
    1610                 :          39 :   void add_boundaries (boundaries &out, logger *logger) const override
    1611                 :             :   {
    1612                 :          39 :     LOG_SCOPE (logger);
    1613                 :          39 :     out.add (m_actual_bits, boundaries::kind::HARD);
    1614                 :          39 :   }
    1615                 :             : 
    1616                 :          34 :   table make_table (const bit_to_table_map &btm,
    1617                 :             :                     style_manager &sm) const override
    1618                 :             :   {
    1619                 :          34 :     table t (table::size_t (btm.get_num_columns (), 0));
    1620                 :             : 
    1621                 :          34 :     const int table_y = t.add_row ();
    1622                 :          34 :     const int table_h = 1;
    1623                 :          34 :     table::rect_t rect = btm.get_table_rect (m_actual_bits, table_y, table_h);
    1624                 :          34 :     t.set_cell_span (rect, styled_string (get_label_string (sm)));
    1625                 :          34 :     return t;
    1626                 :             :   }
    1627                 :             : 
    1628                 :             : protected:
    1629                 :          34 :   styled_string get_label_string (style_manager &sm) const
    1630                 :             :   {
    1631                 :          34 :     tree rep_tree = m_op.m_model.get_representative_tree (&m_sval);
    1632                 :          34 :     if (rep_tree)
    1633                 :             :       {
    1634                 :          30 :         if (TREE_CODE (rep_tree) == SSA_NAME)
    1635                 :          14 :           rep_tree = SSA_NAME_VAR (rep_tree);
    1636                 :          30 :         switch (TREE_CODE (rep_tree))
    1637                 :             :           {
    1638                 :             :           default:
    1639                 :             :             break;
    1640                 :          16 :           case INTEGER_CST:
    1641                 :          32 :             return fmt_styled_string (sm, _("write of %<(%T) %E%>"),
    1642                 :          16 :                                       TREE_TYPE (rep_tree),
    1643                 :          16 :                                       rep_tree);
    1644                 :             : 
    1645                 :          14 :           case PARM_DECL:
    1646                 :          14 :           case VAR_DECL:
    1647                 :          28 :             return fmt_styled_string (sm, _("write from %qE (type: %qT)"),
    1648                 :             :                                       rep_tree,
    1649                 :          14 :                                       TREE_TYPE (rep_tree));
    1650                 :             :             break;
    1651                 :             :           }
    1652                 :             :         }
    1653                 :             : 
    1654                 :           4 :     const access_range accessed_bits (m_op.get_actual_bits ());
    1655                 :           4 :     return get_access_size_str (sm,
    1656                 :             :                                 m_op,
    1657                 :             :                                 accessed_bits,
    1658                 :           4 :                                 m_sval.get_type ());
    1659                 :             :   }
    1660                 :             : 
    1661                 :             :   const access_operation &m_op;
    1662                 :             :   const svalue &m_sval;
    1663                 :             :   access_range m_actual_bits;
    1664                 :             : };
    1665                 :             : 
    1666                 :             : /* Subclass of svalue_spatial_item for initial_svalue of a string_region
    1667                 :             :    i.e. for string literals.
    1668                 :             : 
    1669                 :             :    There are three cases:
    1670                 :             :    (a) for long strings, show just the head and tail of the string,
    1671                 :             :    with an ellipsis:
    1672                 :             :      +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
    1673                 :             :      |[0]|[1]|[2]|[3]|[4]|[5]|          |[440]|[441]|[442]|[443]|[444]|[445]|
    1674                 :             :      +---+---+---+---+---+---+   ...    +-----+-----+-----+-----+-----+-----+
    1675                 :             :      |‘L’|‘o’|‘r’|‘e’|‘m’|‘ ’|          | ‘o’ | ‘r’ | ‘u’ | ‘m’ | ‘.’ | NUL |
    1676                 :             :      +---+---+---+---+---+---+----------+-----+-----+-----+-----+-----+-----+
    1677                 :             :      |                  string literal (type: ‘char[446]’)                  |
    1678                 :             :      +----------------------------------------------------------------------+
    1679                 :             :    (b) For sufficiently short strings, show the full string:
    1680                 :             :      +----------+---------+---------+---------+---------+ +-----------------+
    1681                 :             :      |   [0]    |   [1]   |   [2]   |   [3]   |   [4]   | |       [5]       |
    1682                 :             :      +----------+---------+---------+---------+---------+ +-----------------+
    1683                 :             :      |   ‘h’    |   ‘e’   |   ‘l’   |   ‘l’   |   ‘o’   | |       NUL       |
    1684                 :             :      +----------+---------+---------+---------+---------+-+-----------------+
    1685                 :             :      |                   string literal (type: ‘char[6]’)                   |
    1686                 :             :      +----------------------------------------------------------------------+
    1687                 :             :    (c) for non-ASCII strings that are short enough to show the full string,
    1688                 :             :    show how unicode code points of the bytes decoded as UTF-8:
    1689                 :             :      +-----+-----+-----+----+----++----+----+----+----+----+----+----+------+
    1690                 :             :      | [0] | [1] | [2] |[3] |[4] ||[5] |[6] |[7] |[8] |[9] |[10]|[11]| [12] |
    1691                 :             :      +-----+-----+-----+----+----++----+----+----+----+----+----+----+------+
    1692                 :             :      |0xe6 |0x96 |0x87 |0xe5|0xad||0x97|0xe5|0x8c|0x96|0xe3|0x81|0x91| 0x00 |
    1693                 :             :      +-----+-----+-----+----+----++----+----+----+----+----+----+----+------+
    1694                 :             :      |     U+6587      |    U+5b57     |    U+5316    |    U+3051    |U+0000|
    1695                 :             :      +-----------------+---------------+--------------+--------------+------+
    1696                 :             :      |                  string literal (type: ‘char[13]’)                   |
    1697                 :             :      +----------------------------------------------------------------------+
    1698                 :             :    and show the characters themselves if unicode is supported and they are not
    1699                 :             :    control characters:
    1700                 :             :      ┌─────┬─────┬─────┬────┬────┐┌────┬────┬────┬────┬────┬────┬────┬──────┐
    1701                 :             :      │ [0] │ [1] │ [2] │[3] │[4] ││[5] │[6] │[7] │[8] │[9] │[10]│[11]│ [12] │
    1702                 :             :      ├─────┼─────┼─────┼────┼────┤├────┼────┼────┼────┼────┼────┼────┼──────┤
    1703                 :             :      │0xe6 │0x96 │0x87 │0xe5│0xad││0x97│0xe5│0x8c│0x96│0xe3│0x81│0x91│ 0x00 │
    1704                 :             :      ├─────┴─────┴─────┼────┴────┴┴────┼────┴────┴────┼────┴────┴────┼──────┤
    1705                 :             :      │     U+6587      │    U+5b57     │    U+5316    │    U+3051    │U+0000│
    1706                 :             :      ├─────────────────┼───────────────┼──────────────┼──────────────┼──────┤
    1707                 :             :      │       文        │      字       │      化      │      け      │ NUL  │
    1708                 :             :      ├─────────────────┴───────────────┴──────────────┴──────────────┴──────┤
    1709                 :             :      │                  string literal (type: ‘char[13]’)                   │
    1710                 :             :      └──────────────────────────────────────────────────────────────────────┘
    1711                 :             : */
    1712                 :             : 
    1713                 :             : class string_literal_spatial_item : public svalue_spatial_item
    1714                 :             : {
    1715                 :             : public:
    1716                 :          34 :   string_literal_spatial_item (const svalue &sval,
    1717                 :             :                                access_range actual_bits,
    1718                 :             :                                const string_region &string_reg,
    1719                 :             :                                const theme &theme,
    1720                 :             :                                enum kind kind)
    1721                 :          34 :   : svalue_spatial_item (sval, actual_bits, kind),
    1722                 :          34 :     m_string_reg (string_reg),
    1723                 :          34 :     m_theme (theme),
    1724                 :          34 :     m_ellipsis_threshold (param_analyzer_text_art_string_ellipsis_threshold),
    1725                 :          34 :     m_ellipsis_head_len (param_analyzer_text_art_string_ellipsis_head_len),
    1726                 :          34 :     m_ellipsis_tail_len (param_analyzer_text_art_string_ellipsis_tail_len),
    1727                 :          68 :     m_show_full_string (calc_show_full_string ()),
    1728                 :          34 :     m_show_utf8 (m_show_full_string && !pure_ascii_p ())
    1729                 :             :   {
    1730                 :          34 :   }
    1731                 :             : 
    1732                 :          34 :   void add_boundaries (boundaries &out, logger *logger) const override
    1733                 :             :   {
    1734                 :          34 :     LOG_SCOPE (logger);
    1735                 :          34 :     out.add (m_bits, m_kind == svalue_spatial_item::kind::WRITTEN
    1736                 :          34 :              ? boundaries::kind::HARD
    1737                 :             :              : boundaries::kind::SOFT);
    1738                 :             : 
    1739                 :          34 :     tree string_cst = get_string_cst ();
    1740                 :             :     /* TREE_STRING_LENGTH is sizeof, not strlen.  */
    1741                 :          34 :     if (m_show_full_string)
    1742                 :          20 :       out.add_all_bytes_in_range (m_bits);
    1743                 :             :     else
    1744                 :             :       {
    1745                 :          14 :         byte_range bytes (0, 0);
    1746                 :          14 :         bool valid = m_bits.as_concrete_byte_range (&bytes);
    1747                 :          14 :         gcc_assert (valid);
    1748                 :          14 :         byte_range head_of_string (bytes.get_start_byte_offset (),
    1749                 :          14 :                                    m_ellipsis_head_len);
    1750                 :          14 :         out.add_all_bytes_in_range (head_of_string);
    1751                 :          14 :         byte_range tail_of_string
    1752                 :          14 :           ((bytes.get_start_byte_offset ()
    1753                 :          14 :             + TREE_STRING_LENGTH (string_cst)
    1754                 :          14 :             - m_ellipsis_tail_len),
    1755                 :          28 :            m_ellipsis_tail_len);
    1756                 :          14 :         out.add_all_bytes_in_range (tail_of_string);
    1757                 :             :         /* Adding the above pair of ranges will also effectively add
    1758                 :             :            the boundaries of the range of ellipsized chars, as they're
    1759                 :             :            exactly in between head_of_string and tail_of_string.  */
    1760                 :             :       }
    1761                 :          34 :   }
    1762                 :             : 
    1763                 :          34 :   table make_table (const bit_to_table_map &btm,
    1764                 :             :                     style_manager &sm) const override
    1765                 :             :   {
    1766                 :          34 :     table t (table::size_t (btm.get_num_columns (), 0));
    1767                 :             : 
    1768                 :          34 :     const int byte_idx_table_y = (m_kind == svalue_spatial_item::kind::WRITTEN
    1769                 :          34 :                                   ? t.add_row ()
    1770                 :          34 :                                   : -1);
    1771                 :          34 :     const int byte_val_table_y = t.add_row ();
    1772                 :             : 
    1773                 :          34 :     byte_range bytes (0, 0);
    1774                 :          34 :     bool valid = m_bits.as_concrete_byte_range (&bytes);
    1775                 :          34 :     gcc_assert (valid);
    1776                 :          34 :     tree string_cst = get_string_cst ();
    1777                 :          34 :     if (m_show_full_string)
    1778                 :             :       {
    1779                 :          20 :        for (byte_offset_t byte_idx_within_cluster
    1780                 :          20 :               = bytes.get_start_byte_offset ();
    1781                 :         168 :             byte_idx_within_cluster < bytes.get_next_byte_offset ();
    1782                 :         148 :             byte_idx_within_cluster = byte_idx_within_cluster + 1)
    1783                 :         148 :          add_column_for_byte
    1784                 :         148 :            (t, btm, sm, byte_idx_within_cluster,
    1785                 :         296 :             byte_idx_within_cluster - bytes.get_start_byte_offset (),
    1786                 :             :             byte_idx_table_y, byte_val_table_y);
    1787                 :             : 
    1788                 :          20 :        if (m_show_utf8)
    1789                 :             :          {
    1790                 :           6 :            const bool show_unichars = m_theme.unicode_p ();
    1791                 :           6 :            const int utf8_code_point_table_y = t.add_row ();
    1792                 :           6 :            int utf8_character_table_y;
    1793                 :           6 :            if (show_unichars)
    1794                 :           5 :              utf8_character_table_y = t.add_row ();
    1795                 :             : 
    1796                 :             :            /* We don't actually want the display widths here, but
    1797                 :             :               it's an easy way to decode UTF-8.  */
    1798                 :           6 :            cpp_char_column_policy policy (8, cpp_wcwidth);
    1799                 :           6 :            cpp_display_width_computation dw (TREE_STRING_POINTER (string_cst),
    1800                 :           6 :                                              TREE_STRING_LENGTH (string_cst),
    1801                 :           6 :                                              policy);
    1802                 :          47 :            while (!dw.done ())
    1803                 :             :              {
    1804                 :          35 :                cpp_decoded_char decoded_char;
    1805                 :          35 :                dw.process_next_codepoint (&decoded_char);
    1806                 :             : 
    1807                 :          35 :                if (!decoded_char.m_valid_ch)
    1808                 :           0 :                  continue;
    1809                 :          35 :                size_t start_byte_idx
    1810                 :          35 :                  = decoded_char.m_start_byte - TREE_STRING_POINTER (string_cst);
    1811                 :          35 :                byte_size_t size_in_bytes
    1812                 :          35 :                  = decoded_char.m_next_byte - decoded_char.m_start_byte;
    1813                 :          35 :                byte_range cluster_bytes_for_codepoint
    1814                 :          35 :                  (start_byte_idx + bytes.get_start_byte_offset (),
    1815                 :          35 :                   size_in_bytes);
    1816                 :             : 
    1817                 :          35 :                const table::rect_t code_point_table_rect
    1818                 :          35 :                  = btm.get_table_rect (&m_string_reg,
    1819                 :             :                                        cluster_bytes_for_codepoint,
    1820                 :             :                                        utf8_code_point_table_y, 1);
    1821                 :          35 :                char buf[100];
    1822                 :          35 :                sprintf (buf, "U+%04x", decoded_char.m_ch);
    1823                 :          35 :                t.set_cell_span (code_point_table_rect,
    1824                 :          35 :                                 styled_string (sm, buf));
    1825                 :             : 
    1826                 :          35 :                if (show_unichars)
    1827                 :             :                  {
    1828                 :          30 :                    const table::rect_t character_table_rect
    1829                 :          30 :                      = btm.get_table_rect (&m_string_reg,
    1830                 :             :                                            cluster_bytes_for_codepoint,
    1831                 :             :                                            utf8_character_table_y, 1);
    1832                 :          30 :                    if (cpp_is_printable_char (decoded_char.m_ch))
    1833                 :          23 :                      t.set_cell_span (character_table_rect,
    1834                 :          46 :                                       styled_string (decoded_char.m_ch));
    1835                 :           7 :                    else if (decoded_char.m_ch == 0)
    1836                 :           5 :                      t.set_cell_span (character_table_rect,
    1837                 :          10 :                                       styled_string (sm, "NUL"));
    1838                 :             :                    else
    1839                 :           2 :                      t.set_cell_span (character_table_rect,
    1840                 :           4 :                                       styled_string (sm, ""));
    1841                 :             :                  }
    1842                 :             :              }
    1843                 :             :          }
    1844                 :             :       }
    1845                 :             :     else
    1846                 :             :       {
    1847                 :             :         /* Head of string.  */
    1848                 :          98 :         for (int byte_idx = 0; byte_idx < m_ellipsis_head_len; byte_idx++)
    1849                 :          84 :           add_column_for_byte (t, btm, sm,
    1850                 :         168 :                                byte_idx + bytes.get_start_byte_offset (),
    1851                 :             :                                byte_idx,
    1852                 :             :                                byte_idx_table_y, byte_val_table_y);
    1853                 :             : 
    1854                 :             :         /* Ellipsis.  */
    1855                 :          14 :         const byte_range ellipsis_bytes
    1856                 :          14 :           (m_ellipsis_head_len + bytes.get_start_byte_offset (),
    1857                 :          14 :            TREE_STRING_LENGTH (string_cst)
    1858                 :          14 :            - (m_ellipsis_head_len + m_ellipsis_tail_len));
    1859                 :          14 :         const table::rect_t table_rect
    1860                 :             :           = ((byte_idx_table_y != -1)
    1861                 :          14 :              ? btm.get_table_rect (&m_string_reg, ellipsis_bytes,
    1862                 :             :                                    byte_idx_table_y, 2)
    1863                 :           7 :              : btm.get_table_rect (&m_string_reg, ellipsis_bytes,
    1864                 :             :                                    byte_val_table_y, 1));
    1865                 :          14 :         t.set_cell_span(table_rect, styled_string (sm, "..."));
    1866                 :             : 
    1867                 :             :         /* Tail of string.  */
    1868                 :          14 :         for (int byte_idx
    1869                 :          14 :                = (TREE_STRING_LENGTH (string_cst) - m_ellipsis_tail_len);
    1870                 :          98 :              byte_idx < TREE_STRING_LENGTH (string_cst);
    1871                 :             :              byte_idx++)
    1872                 :          84 :           add_column_for_byte (t, btm, sm,
    1873                 :         168 :                                byte_idx + bytes.get_start_byte_offset (),
    1874                 :             :                                byte_idx,
    1875                 :             :                                byte_idx_table_y, byte_val_table_y);
    1876                 :             :       }
    1877                 :             : 
    1878                 :          34 :     if (m_kind == svalue_spatial_item::kind::WRITTEN)
    1879                 :             :       {
    1880                 :          19 :         const int summary_table_y = t.add_row ();
    1881                 :          19 :         t.set_cell_span (btm.get_table_rect (&m_string_reg, bytes,
    1882                 :             :                                              summary_table_y, 1),
    1883                 :          19 :                          fmt_styled_string (sm,
    1884                 :          19 :                                             _("string literal (type: %qT)"),
    1885                 :          19 :                                             TREE_TYPE (string_cst)));
    1886                 :             :       }
    1887                 :             : 
    1888                 :          34 :     return t;
    1889                 :             :   }
    1890                 :             : 
    1891                 :          68 :   tree get_string_cst () const { return m_string_reg.get_string_cst (); }
    1892                 :             : 
    1893                 :             : private:
    1894                 :          34 :   bool calc_show_full_string () const
    1895                 :             :   {
    1896                 :          34 :     tree string_cst = get_string_cst ();
    1897                 :          34 :     if (TREE_STRING_LENGTH (string_cst) < m_ellipsis_threshold)
    1898                 :             :       return true;
    1899                 :          15 :     if (TREE_STRING_LENGTH (string_cst) <
    1900                 :          15 :         (m_ellipsis_head_len + m_ellipsis_tail_len))
    1901                 :           1 :       return true;
    1902                 :             :     return false;
    1903                 :             :   }
    1904                 :             : 
    1905                 :          20 :   bool pure_ascii_p () const
    1906                 :             :   {
    1907                 :          20 :     tree string_cst = get_string_cst ();
    1908                 :         117 :     for (unsigned byte_idx = 0;
    1909                 :         117 :          byte_idx < (unsigned) TREE_STRING_LENGTH (string_cst);
    1910                 :             :          byte_idx++)
    1911                 :             :       {
    1912                 :         103 :         unsigned char ch = TREE_STRING_POINTER (string_cst)[byte_idx];
    1913                 :         103 :         if (ch >= 0x80)
    1914                 :             :           return false;
    1915                 :             :       }
    1916                 :             :     return true;
    1917                 :             :   }
    1918                 :             : 
    1919                 :         316 :   void add_column_for_byte (table &t, const bit_to_table_map &btm,
    1920                 :             :                             style_manager &sm,
    1921                 :             :                             const byte_offset_t byte_idx_within_cluster,
    1922                 :             :                             const byte_offset_t byte_idx_within_string,
    1923                 :             :                             const int byte_idx_table_y,
    1924                 :             :                             const int byte_val_table_y) const
    1925                 :             :   {
    1926                 :         316 :     tree string_cst = get_string_cst ();
    1927                 :         316 :     gcc_assert (byte_idx_within_string >= 0);
    1928                 :         316 :     gcc_assert (byte_idx_within_string < TREE_STRING_LENGTH (string_cst));
    1929                 :             : 
    1930                 :         316 :     const byte_range bytes (byte_idx_within_cluster, 1);
    1931                 :         316 :     if (byte_idx_table_y != -1)
    1932                 :             :       {
    1933                 :         186 :         const table::rect_t idx_table_rect
    1934                 :         186 :           = btm.get_table_rect (&m_string_reg, bytes, byte_idx_table_y, 1);
    1935                 :         186 :         t.set_cell_span (idx_table_rect,
    1936                 :         372 :                          fmt_styled_string (sm, "[%wu]",
    1937                 :             :                                             byte_idx_within_string.ulow ()));
    1938                 :             :       }
    1939                 :             : 
    1940                 :         316 :     char byte_val
    1941                 :         316 :       = TREE_STRING_POINTER (string_cst)[byte_idx_within_string.ulow ()];
    1942                 :         316 :     const table::rect_t val_table_rect
    1943                 :         316 :       = btm.get_table_rect (&m_string_reg, bytes, byte_val_table_y, 1);
    1944                 :         316 :     table_cell_content content (make_cell_content_for_byte (sm, byte_val));
    1945                 :         316 :     t.set_cell_span (val_table_rect, std::move (content));
    1946                 :         316 :   }
    1947                 :             : 
    1948                 :         316 :   table_cell_content make_cell_content_for_byte (style_manager &sm,
    1949                 :             :                                                  unsigned char byte_val) const
    1950                 :             :   {
    1951                 :         316 :     if (!m_show_utf8)
    1952                 :             :        {
    1953                 :         253 :         if (byte_val == '\0')
    1954                 :          28 :           return styled_string (sm, "NUL");
    1955                 :         225 :         else if (byte_val < 0x80)
    1956                 :         225 :           if (ISPRINT (byte_val))
    1957                 :         221 :             return fmt_styled_string (sm, "%qc", byte_val);
    1958                 :             :        }
    1959                 :          67 :     char buf[100];
    1960                 :          67 :     sprintf (buf, "0x%02x", byte_val);
    1961                 :          67 :     return styled_string (sm, buf);
    1962                 :             :   }
    1963                 :             : 
    1964                 :             :   const string_region &m_string_reg;
    1965                 :             :   const theme &m_theme;
    1966                 :             :   const int m_ellipsis_threshold;
    1967                 :             :   const int m_ellipsis_head_len;
    1968                 :             :   const int m_ellipsis_tail_len;
    1969                 :             :   const bool m_show_full_string;
    1970                 :             :   const bool m_show_utf8;
    1971                 :             : };
    1972                 :             : 
    1973                 :             : static std::unique_ptr<spatial_item>
    1974                 :          58 : make_written_svalue_spatial_item (const access_operation &op,
    1975                 :             :                                   const svalue &sval,
    1976                 :             :                                   access_range actual_bits,
    1977                 :             :                                   const theme &theme)
    1978                 :             : {
    1979                 :          58 :   if (const initial_svalue *initial_sval = sval.dyn_cast_initial_svalue ())
    1980                 :          36 :     if (const string_region *string_reg
    1981                 :          36 :         = initial_sval->get_region ()->dyn_cast_string_region ())
    1982                 :          19 :       return make_unique <string_literal_spatial_item>
    1983                 :          19 :         (sval, actual_bits,
    1984                 :             :          *string_reg, theme,
    1985                 :          19 :          svalue_spatial_item::kind::WRITTEN);
    1986                 :          39 :   return make_unique <written_svalue_spatial_item> (op, sval, actual_bits);
    1987                 :             : }
    1988                 :             : 
    1989                 :             : static std::unique_ptr<spatial_item>
    1990                 :         104 : make_existing_svalue_spatial_item (const svalue *sval,
    1991                 :             :                                    const access_range &bits,
    1992                 :             :                                    const theme &theme)
    1993                 :             : {
    1994                 :         104 :   if (!sval)
    1995                 :           0 :     return nullptr;
    1996                 :             : 
    1997                 :         104 :   switch (sval->get_kind ())
    1998                 :             :     {
    1999                 :          61 :     default:
    2000                 :          61 :       return nullptr;
    2001                 :             : 
    2002                 :          30 :     case SK_INITIAL:
    2003                 :          30 :       {
    2004                 :          30 :         const initial_svalue *initial_sval = (const initial_svalue *)sval;
    2005                 :          30 :         if (const string_region *string_reg
    2006                 :          30 :             = initial_sval->get_region ()->dyn_cast_string_region ())
    2007                 :          15 :           return make_unique <string_literal_spatial_item>
    2008                 :          15 :             (*sval, bits,
    2009                 :             :              *string_reg, theme,
    2010                 :          15 :              svalue_spatial_item::kind::EXISTING);
    2011                 :          15 :         return nullptr;
    2012                 :             :       }
    2013                 :             : 
    2014                 :          13 :     case SK_COMPOUND:
    2015                 :          13 :       return make_unique<compound_svalue_spatial_item>
    2016                 :          13 :         (*((const compound_svalue *)sval),
    2017                 :             :          bits,
    2018                 :          26 :          svalue_spatial_item::kind::EXISTING,
    2019                 :          13 :          theme);
    2020                 :             :     }
    2021                 :             : }
    2022                 :             : 
    2023                 :             : /* Widget subclass implementing access diagrams.  */
    2024                 :             : 
    2025                 :             : class access_diagram_impl : public vbox_widget
    2026                 :             : {
    2027                 :             : public:
    2028                 :          73 :   access_diagram_impl (const access_operation &op,
    2029                 :             :                        diagnostic_event_id_t region_creation_event_id,
    2030                 :             :                        style_manager &sm,
    2031                 :             :                        const theme &theme,
    2032                 :             :                        logger *logger)
    2033                 :          73 :   : m_op (op),
    2034                 :          73 :     m_region_creation_event_id (region_creation_event_id),
    2035                 :          73 :     m_sm (sm),
    2036                 :          73 :     m_theme (theme),
    2037                 :          73 :     m_logger (logger),
    2038                 :          73 :     m_invalid (false),
    2039                 :          73 :     m_valid_region_spatial_item (op, region_creation_event_id, theme),
    2040                 :          73 :     m_accessed_region_spatial_item (op),
    2041                 :          73 :     m_btm (),
    2042                 :          73 :     m_calc_req_size_called (false)
    2043                 :             :   {
    2044                 :          73 :     LOG_SCOPE (logger);
    2045                 :             : 
    2046                 :          73 :     if (logger)
    2047                 :             :       {
    2048                 :           0 :         access_range invalid_before_bits;
    2049                 :           0 :         if (op.maybe_get_invalid_before_bits (&invalid_before_bits))
    2050                 :           0 :           invalid_before_bits.log ("invalid before range", *logger);
    2051                 :           0 :         access_range invalid_after_bits;
    2052                 :           0 :         if (op.maybe_get_invalid_after_bits (&invalid_after_bits))
    2053                 :           0 :           invalid_after_bits.log ("invalid after range", *logger);
    2054                 :             : 
    2055                 :           0 :         if (op.m_sval_hint)
    2056                 :             :           {
    2057                 :           0 :             logger->start_log_line ();
    2058                 :           0 :             logger->log_partial ("sval_hint: ");
    2059                 :           0 :             op.m_sval_hint->dump_to_pp (logger->get_printer (), true);
    2060                 :           0 :             logger->end_log_line ();
    2061                 :             :           }
    2062                 :             :       }
    2063                 :             : 
    2064                 :             :     /* Register painting styles.  */
    2065                 :          73 :     {
    2066                 :          73 :       style valid_style (get_style_from_color_cap_name ("valid"));
    2067                 :          73 :       m_valid_style_id = m_sm.get_or_create_id (valid_style);
    2068                 :             : 
    2069                 :          73 :       style invalid_style (get_style_from_color_cap_name ("invalid"));
    2070                 :          73 :       m_invalid_style_id = m_sm.get_or_create_id (invalid_style);
    2071                 :          73 :     }
    2072                 :             : 
    2073                 :          73 :     if (op.m_sval_hint)
    2074                 :             :       {
    2075                 :          58 :         access_range actual_bits = m_op.get_actual_bits ();
    2076                 :          58 :         m_written_svalue_spatial_item
    2077                 :          58 :           = make_written_svalue_spatial_item (m_op,
    2078                 :          58 :                                               *op.m_sval_hint,
    2079                 :             :                                               actual_bits,
    2080                 :          58 :                                               m_theme);
    2081                 :             :       }
    2082                 :             : 
    2083                 :             :     /* Two passes:
    2084                 :             :        First, figure out all of the boundaries of interest.
    2085                 :             :        Then use that to build child widgets showing the regions of interest,
    2086                 :             :        with a common tabular layout.  */
    2087                 :             : 
    2088                 :          73 :     m_boundaries = find_boundaries ();
    2089                 :          73 :     if (logger)
    2090                 :           0 :       m_boundaries->log (*logger);
    2091                 :             : 
    2092                 :             :     /* Populate m_table_x_for_bit and m_bit_for_table_x.
    2093                 :             :        Each table column represents the range [offset, next_offset).
    2094                 :             :        We don't create a column in the table for the final offset, but we
    2095                 :             :        do populate it, so that looking at the table_x of one beyond the
    2096                 :             :        final table column gives us the upper bound offset.  */
    2097                 :          73 :     m_btm.populate (*m_boundaries, *m_op.get_manager (), logger);
    2098                 :             : 
    2099                 :             :     /* Gracefully reject cases where the boundary sorting has gone wrong
    2100                 :             :        (due to awkward combinations of symbolic values).  */
    2101                 :          73 :     {
    2102                 :          73 :       table::range_t actual_bits_x_range
    2103                 :          73 :         = m_btm.get_table_x_for_range (m_op.get_actual_bits ());
    2104                 :          73 :       if (actual_bits_x_range.get_size () <= 0)
    2105                 :             :         {
    2106                 :           5 :           if (logger)
    2107                 :           0 :             logger->log ("giving up: bad table columns for actual_bits");
    2108                 :           5 :           m_invalid = true;
    2109                 :           5 :           return;
    2110                 :             :         }
    2111                 :          68 :       table::range_t valid_bits_x_range
    2112                 :          68 :         = m_btm.get_table_x_for_range (m_op.get_valid_bits ());
    2113                 :          68 :       if (valid_bits_x_range.get_size () <= 0)
    2114                 :             :         {
    2115                 :           0 :           if (logger)
    2116                 :           0 :             logger->log ("giving up: bad table columns for valid_bits");
    2117                 :           0 :           m_invalid = true;
    2118                 :           0 :           return;
    2119                 :             :         }
    2120                 :             :     }
    2121                 :             : 
    2122                 :          68 :     m_col_widths
    2123                 :          68 :       = make_unique <table_dimension_sizes> (m_btm.get_num_columns ());
    2124                 :             : 
    2125                 :             :     /* Now create child widgets.  */
    2126                 :             : 
    2127                 :          68 :     if (flag_analyzer_debug_text_art)
    2128                 :             :       {
    2129                 :           1 :         table t_headings (make_headings_table ());
    2130                 :           2 :         add_aligned_child_table (std::move (t_headings));
    2131                 :           1 :       }
    2132                 :             : 
    2133                 :          68 :     if (m_written_svalue_spatial_item)
    2134                 :             :       {
    2135                 :          53 :         table t_sval (m_written_svalue_spatial_item->make_table (m_btm, m_sm));
    2136                 :         106 :         add_aligned_child_table (std::move (t_sval));
    2137                 :          53 :       }
    2138                 :             :     else
    2139                 :             :       {
    2140                 :          15 :         table t_accessed
    2141                 :          15 :           (m_accessed_region_spatial_item.make_table (m_btm, m_sm));
    2142                 :          30 :         add_aligned_child_table (std::move (t_accessed));
    2143                 :          15 :       }
    2144                 :             : 
    2145                 :          68 :     add_direction_widget ();
    2146                 :             : 
    2147                 :          68 :     table t_valid (m_valid_region_spatial_item.make_table (m_btm, m_sm));
    2148                 :          68 :     add_invalid_accesses_to_region_table (t_valid);
    2149                 :          68 :     add_aligned_child_table (std::move (t_valid));
    2150                 :             : 
    2151                 :          68 :     add_valid_vs_invalid_ruler ();
    2152                 :          73 :   }
    2153                 :             : 
    2154                 :           0 :   const char *get_desc () const override
    2155                 :             :   {
    2156                 :           0 :     return "access_diagram_impl";
    2157                 :             :   }
    2158                 :             : 
    2159                 :          73 :   canvas::size_t calc_req_size () final override
    2160                 :             :   {
    2161                 :          73 :     if (m_invalid)
    2162                 :           5 :       return canvas::size_t (0, 0);
    2163                 :             : 
    2164                 :             :     /* Now compute the size requirements for the tables.  */
    2165                 :         205 :     for (auto iter : m_aligned_table_widgets)
    2166                 :         137 :       iter->get_cell_sizes ().pass_1 (iter->get_table ());
    2167                 :         205 :     for (auto iter : m_aligned_table_widgets)
    2168                 :         137 :       iter->get_cell_sizes ().pass_2 (iter->get_table ());
    2169                 :             : 
    2170                 :          68 :     adjust_to_scale();
    2171                 :             : 
    2172                 :             :     /* ...and relayout the tables.  */
    2173                 :         205 :     for (auto iter : m_aligned_table_widgets)
    2174                 :         137 :       iter->recalc_coords ();
    2175                 :             : 
    2176                 :             :     /* Populate the canvas_x per table_x.  */
    2177                 :          68 :     m_col_start_x.clear ();
    2178                 :          68 :     int iter_canvas_x = 0;
    2179                 :         672 :     for (auto w : m_col_widths->m_requirements)
    2180                 :             :       {
    2181                 :         604 :         m_col_start_x.push_back (iter_canvas_x);
    2182                 :         604 :         iter_canvas_x += w + 1;
    2183                 :             :       }
    2184                 :          68 :     m_col_start_x.push_back (iter_canvas_x);
    2185                 :             : 
    2186                 :          68 :     m_calc_req_size_called = true;
    2187                 :             : 
    2188                 :          68 :     return vbox_widget::calc_req_size ();
    2189                 :             :   }
    2190                 :             : 
    2191                 :        1224 :   int get_canvas_x_for_table_x (int table_x) const
    2192                 :             :   {
    2193                 :        1224 :     gcc_assert (m_calc_req_size_called);
    2194                 :        1224 :     return m_col_start_x[table_x];
    2195                 :             :   }
    2196                 :             : 
    2197                 :         612 :   canvas::range_t get_canvas_x_range (const table::range_t &table_x_range) const
    2198                 :             :   {
    2199                 :         612 :     gcc_assert (m_calc_req_size_called);
    2200                 :         612 :     return canvas::range_t (get_canvas_x_for_table_x (table_x_range.start),
    2201                 :         612 :                             get_canvas_x_for_table_x (table_x_range.next));
    2202                 :             :   }
    2203                 :             : 
    2204                 :         436 :   const access_operation &get_op () const { return m_op; }
    2205                 :             : 
    2206                 :         300 :   style::id_t get_style_id_for_validity (bool is_valid) const
    2207                 :             :   {
    2208                 :         300 :     return is_valid ? m_valid_style_id : m_invalid_style_id;
    2209                 :             :   }
    2210                 :             : 
    2211                 :         300 :   const theme &get_theme () const { return m_theme; }
    2212                 :             : 
    2213                 :             : private:
    2214                 :             :   /* Figure out all of the boundaries of interest when visualizing ths op.  */
    2215                 :             :   std::unique_ptr<boundaries>
    2216                 :          73 :   find_boundaries () const
    2217                 :             :   {
    2218                 :          73 :     std::unique_ptr<boundaries> result
    2219                 :          73 :       = make_unique<boundaries> (*m_op.m_base_region, m_logger);
    2220                 :             : 
    2221                 :          73 :     m_valid_region_spatial_item.add_boundaries (*result, m_logger);
    2222                 :          73 :     m_accessed_region_spatial_item.add_boundaries (*result, m_logger);
    2223                 :          73 :     if (m_written_svalue_spatial_item)
    2224                 :          58 :       m_written_svalue_spatial_item->add_boundaries (*result, m_logger);
    2225                 :             : 
    2226                 :          73 :     return result;
    2227                 :             :   }
    2228                 :             : 
    2229                 :         137 :   void add_aligned_child_table (table t)
    2230                 :             :   {
    2231                 :         137 :     x_aligned_table_widget *w
    2232                 :         137 :       = new x_aligned_table_widget (std::move (t), m_theme, *m_col_widths);
    2233                 :         137 :     m_aligned_table_widgets.push_back (w);
    2234                 :         137 :     add_child (std::unique_ptr<widget> (w));
    2235                 :         137 :   }
    2236                 :             : 
    2237                 :             :   /* Create a table showing headings for use by -fanalyzer-debug-text-art, for
    2238                 :             :      example:
    2239                 :             :      +---------+-----------+-----------+---+--------------------------------+
    2240                 :             :      |   tc0   |    tc1    |    tc2    |tc3|              tc4               |
    2241                 :             :      +---------+-----------+-----------+---+--------------------------------+
    2242                 :             :      |bytes 0-3|bytes 4-35 |bytes 36-39|   |          bytes 40-43           |
    2243                 :             :      +---------+-----------+-----------+   +--------------------------------+
    2244                 :             :      which has:
    2245                 :             :      - a row showing the table column numbers, labelled "tc0", "tc1", etc
    2246                 :             :      - a row showing the memory range of each table column that has one.  */
    2247                 :             : 
    2248                 :           1 :   table make_headings_table () const
    2249                 :             :   {
    2250                 :           1 :     table t (table::size_t (m_btm.get_num_columns (), 2));
    2251                 :             : 
    2252                 :           6 :     for (int table_x = 0; table_x < t.get_size ().w; table_x++)
    2253                 :             :       {
    2254                 :           5 :         const int table_y = 0;
    2255                 :           5 :         t.set_cell (table::coord_t (table_x, table_y),
    2256                 :          10 :                     fmt_styled_string (m_sm, "tc%i", table_x));
    2257                 :             :       }
    2258                 :           6 :     for (int table_x = 0; table_x < t.get_size ().w; table_x++)
    2259                 :             :       {
    2260                 :           5 :         const int table_y = 1;
    2261                 :           5 :         access_range range_for_column (NULL, bit_range (0, 0));
    2262                 :           5 :         if (m_btm.maybe_get_access_range_for_table_x (table_x,
    2263                 :             :                                                       &range_for_column))
    2264                 :             :           {
    2265                 :           4 :             pretty_printer pp;
    2266                 :           4 :             pp_format_decoder (&pp) = default_tree_printer;
    2267                 :           4 :             range_for_column.dump_to_pp (&pp, true);
    2268                 :           4 :             t.set_cell (table::coord_t (table_x, table_y),
    2269                 :           4 :                         styled_string (m_sm, pp_formatted_text (&pp)));
    2270                 :           4 :           }
    2271                 :             :       }
    2272                 :             : 
    2273                 :           1 :     return t;
    2274                 :             :   }
    2275                 :             : 
    2276                 :          68 :   void add_direction_widget ()
    2277                 :             :   {
    2278                 :          68 :     add_child (::make_unique<direction_widget> (*this, m_btm));
    2279                 :          68 :   }
    2280                 :             : 
    2281                 :          68 :   void add_invalid_accesses_to_region_table (table &t_region)
    2282                 :             :   {
    2283                 :          68 :     gcc_assert (t_region.get_size ().w == (int)m_btm.get_num_columns ());
    2284                 :             : 
    2285                 :          68 :     const int table_y = 0;
    2286                 :          68 :     const int table_h = t_region.get_size ().h;
    2287                 :             : 
    2288                 :          68 :     access_range invalid_before_bits;
    2289                 :          68 :     if (m_op.maybe_get_invalid_before_bits (&invalid_before_bits))
    2290                 :             :       {
    2291                 :           7 :         t_region.set_cell_span (m_btm.get_table_rect (invalid_before_bits,
    2292                 :             :                                                       table_y, table_h),
    2293                 :           7 :                                 styled_string (m_sm,
    2294                 :           7 :                                                _("before valid range")));
    2295                 :             :       }
    2296                 :          68 :     access_range invalid_after_bits;
    2297                 :          68 :     if (m_op.maybe_get_invalid_after_bits (&invalid_after_bits))
    2298                 :             :       {
    2299                 :          65 :         t_region.set_cell_span (m_btm.get_table_rect (invalid_after_bits,
    2300                 :             :                                                       table_y, table_h),
    2301                 :          65 :                                 styled_string (m_sm,
    2302                 :          65 :                                                _("after valid range")));
    2303                 :             :       }
    2304                 :          68 :   }
    2305                 :             : 
    2306                 :         133 :   void maybe_add_gap (x_aligned_x_ruler_widget *w,
    2307                 :             :                       const access_range &lower,
    2308                 :             :                       const access_range &upper) const
    2309                 :             :   {
    2310                 :         133 :     LOG_SCOPE (m_logger);
    2311                 :         133 :     if (m_logger)
    2312                 :             :       {
    2313                 :           0 :         lower.log ("lower", *m_logger);
    2314                 :           0 :         upper.log ("upper", *m_logger);
    2315                 :             :       }
    2316                 :         133 :     region_model_manager *mgr = m_op.get_manager ();
    2317                 :         133 :     const svalue &lower_next = lower.m_next.calc_symbolic_bit_offset (mgr);
    2318                 :         133 :     const svalue &upper_start = upper.m_start.calc_symbolic_bit_offset (mgr);
    2319                 :         133 :     const svalue *num_bits_gap
    2320                 :         133 :       = mgr->get_or_create_binop (NULL_TREE, MINUS_EXPR,
    2321                 :             :                                   &upper_start, &lower_next);
    2322                 :         133 :     if (m_logger)
    2323                 :           0 :       m_logger->log ("num_bits_gap: %qs", num_bits_gap->get_desc ().get ());
    2324                 :             : 
    2325                 :         133 :     const svalue *zero = mgr->get_or_create_int_cst (NULL_TREE, 0);
    2326                 :         133 :     tristate ts_gt_zero = m_op.m_model.eval_condition (num_bits_gap,
    2327                 :             :                                                        GT_EXPR,
    2328                 :             :                                                        zero);
    2329                 :         133 :     if (ts_gt_zero.is_false ())
    2330                 :             :       {
    2331                 :         116 :         if (m_logger)
    2332                 :           0 :           m_logger->log ("rejecting as not > 0");
    2333                 :         116 :         return;
    2334                 :             :       }
    2335                 :             : 
    2336                 :          17 :     bit_size_expr num_bits (*num_bits_gap);
    2337                 :          17 :     if (auto p = num_bits.maybe_get_formatted_str (m_sm, m_op.m_model,
    2338                 :          17 :                                                    _("%wi bit"),
    2339                 :          17 :                                                    _("%wi bits"),
    2340                 :          17 :                                                    _("%wi byte"),
    2341                 :          17 :                                                    _("%wi bytes"),
    2342                 :          17 :                                                    _("%qs bits"),
    2343                 :          17 :                                                    _("%qs bytes")))
    2344                 :             :       {
    2345                 :          17 :         styled_string label = std::move (*p.get ());
    2346                 :          34 :         w->add_range (m_btm.get_table_x_for_range
    2347                 :          34 :                       (access_range (lower.m_next,
    2348                 :             :                                      upper.m_start,
    2349                 :             :                                      *mgr)),
    2350                 :             :                       std::move (label),
    2351                 :             :                       style::id_plain);
    2352                 :          17 :       }
    2353                 :         133 :   }
    2354                 :             : 
    2355                 :             :   styled_string
    2356                 :          72 :   make_warning_string (styled_string &&text)
    2357                 :             :   {
    2358                 :          72 :     styled_string result;
    2359                 :          72 :     if (!m_theme.emojis_p ())
    2360                 :          71 :       return std::move (text);
    2361                 :             : 
    2362                 :           1 :     result.append (styled_string (0x26A0, /* U+26A0 WARNING SIGN.  */
    2363                 :             :                                   true));
    2364                 :             :     /* U+26A0 WARNING SIGN has East_Asian_Width == Neutral, but in its
    2365                 :             :        emoji variant is printed (by vte at least) with a 2nd half
    2366                 :             :        overlapping the next char.  Hence we add two spaces here: a space
    2367                 :             :        to be covered by this overlap, plus another space of padding.  */
    2368                 :           1 :     result.append (styled_string (m_sm, "  "));
    2369                 :           1 :     result.append (std::move (text));
    2370                 :           1 :     return result;
    2371                 :          72 :   }
    2372                 :             : 
    2373                 :             :   /* Add a ruler child widet showing valid, invalid, and gaps.  */
    2374                 :          68 :   void add_valid_vs_invalid_ruler ()
    2375                 :             :   {
    2376                 :          68 :     LOG_SCOPE (m_logger);
    2377                 :             : 
    2378                 :          68 :     x_aligned_x_ruler_widget *w
    2379                 :          68 :       = new x_aligned_x_ruler_widget (*this, m_theme);
    2380                 :             : 
    2381                 :          68 :     access_range invalid_before_bits;
    2382                 :          68 :     if (m_op.maybe_get_invalid_before_bits (&invalid_before_bits))
    2383                 :             :       {
    2384                 :           7 :         if (m_logger)
    2385                 :           0 :           invalid_before_bits.log ("invalid_before_bits", *m_logger);
    2386                 :           7 :         bit_size_expr num_before_bits
    2387                 :           7 :           (invalid_before_bits.get_size (m_op.get_manager ()));
    2388                 :           7 :         std::unique_ptr<styled_string> label;
    2389                 :           7 :         if (m_op.m_dir == DIR_READ)
    2390                 :           4 :           label = num_before_bits.maybe_get_formatted_str
    2391                 :           8 :             (m_sm, m_op.m_model,
    2392                 :           4 :              _("under-read of %wi bit"),
    2393                 :           4 :              _("under-read of %wi bits"),
    2394                 :           4 :              _("under-read of %wi byte"),
    2395                 :           4 :              _("under-read of %wi bytes"),
    2396                 :           4 :              _("under-read of %qs bits"),
    2397                 :           8 :              _("under-read of %qs bytes"));
    2398                 :             :         else
    2399                 :           3 :           label = num_before_bits.maybe_get_formatted_str
    2400                 :           6 :             (m_sm, m_op.m_model,
    2401                 :           3 :              _("underwrite of %wi bit"),
    2402                 :           3 :              _("underwrite of %wi bits"),
    2403                 :           3 :              _("underwrite of %wi byte"),
    2404                 :           3 :              _("underwrite of %wi bytes"),
    2405                 :           3 :              _("underwrite of %qs bits"),
    2406                 :           6 :              _("underwrite of %qs bytes"));
    2407                 :           7 :         if (label)
    2408                 :           7 :           w->add_range (m_btm.get_table_x_for_range (invalid_before_bits),
    2409                 :          14 :                         make_warning_string (std::move (*label)),
    2410                 :           7 :                         m_invalid_style_id);
    2411                 :           7 :       }
    2412                 :             :     else
    2413                 :             :       {
    2414                 :          61 :         if (m_logger)
    2415                 :           0 :           m_logger->log ("no invalid_before_bits");
    2416                 :             :       }
    2417                 :             : 
    2418                 :             :     /* It would be nice to be able to use std::optional<access_range> here,
    2419                 :             :        but std::optional is C++17.  */
    2420                 :          68 :     bool got_valid_bits = false;
    2421                 :          68 :     access_range valid_bits (m_op.get_valid_bits ());
    2422                 :          68 :     bit_size_expr num_valid_bits (valid_bits.get_size (m_op.get_manager ()));
    2423                 :          68 :     if (m_logger)
    2424                 :           0 :       valid_bits.log ("valid_bits", *m_logger);
    2425                 :             : 
    2426                 :          68 :     got_valid_bits = true;
    2427                 :          68 :     maybe_add_gap (w, invalid_before_bits, valid_bits);
    2428                 :             : 
    2429                 :          68 :     std::unique_ptr<styled_string> label;
    2430                 :          68 :     if (m_op.m_dir == DIR_READ)
    2431                 :          30 :       label = num_valid_bits.maybe_get_formatted_str (m_sm,
    2432                 :          15 :                                                       m_op.m_model,
    2433                 :          15 :                                                       _("size: %wi bit"),
    2434                 :          15 :                                                       _("size: %wi bits"),
    2435                 :          15 :                                                       _("size: %wi byte"),
    2436                 :          15 :                                                       _("size: %wi bytes"),
    2437                 :          15 :                                                       _("size: %qs bits"),
    2438                 :          30 :                                                       _("size: %qs bytes"));
    2439                 :             :     else
    2440                 :          53 :       label
    2441                 :         106 :         = num_valid_bits.maybe_get_formatted_str (m_sm,
    2442                 :          53 :                                                   m_op.m_model,
    2443                 :          53 :                                                   _("capacity: %wi bit"),
    2444                 :          53 :                                                   _("capacity: %wi bits"),
    2445                 :          53 :                                                   _("capacity: %wi byte"),
    2446                 :          53 :                                                   _("capacity: %wi bytes"),
    2447                 :          53 :                                                   _("capacity: %qs bits"),
    2448                 :         106 :                                                   _("capacity: %qs bytes"));
    2449                 :          68 :     if (label)
    2450                 :          67 :       w->add_range (m_btm.get_table_x_for_range (m_op.get_valid_bits ()),
    2451                 :          67 :                     std::move (*label),
    2452                 :          67 :                     m_valid_style_id);
    2453                 :             : 
    2454                 :          68 :     access_range invalid_after_bits;
    2455                 :          68 :     if (m_op.maybe_get_invalid_after_bits (&invalid_after_bits))
    2456                 :             :       {
    2457                 :          65 :         if (got_valid_bits)
    2458                 :          65 :           maybe_add_gap (w, valid_bits, invalid_after_bits);
    2459                 :             : 
    2460                 :          65 :         if (m_logger)
    2461                 :           0 :           invalid_before_bits.log ("invalid_after_bits", *m_logger);
    2462                 :             : 
    2463                 :          65 :         bit_size_expr num_after_bits
    2464                 :          65 :           (invalid_after_bits.get_size (m_op.get_manager ()));
    2465                 :          65 :         std::unique_ptr<styled_string> label;
    2466                 :          65 :         if (m_op.m_dir == DIR_READ)
    2467                 :          13 :           label = num_after_bits.maybe_get_formatted_str
    2468                 :          26 :             (m_sm, m_op.m_model,
    2469                 :          13 :              _("over-read of %wi bit"),
    2470                 :          13 :              _("over-read of %wi bits"),
    2471                 :          13 :              _("over-read of %wi byte"),
    2472                 :          13 :              _("over-read of %wi bytes"),
    2473                 :          13 :              _("over-read of %qs bits"),
    2474                 :          26 :              _("over-read of %qs bytes"));
    2475                 :             :         else
    2476                 :          52 :           label = num_after_bits.maybe_get_formatted_str
    2477                 :         104 :             (m_sm, m_op.m_model,
    2478                 :          52 :              _("overflow of %wi bit"),
    2479                 :          52 :              _("overflow of %wi bits"),
    2480                 :          52 :              _("overflow of %wi byte"),
    2481                 :          52 :              _("overflow of %wi bytes"),
    2482                 :          52 :              _("overflow of %qs bits"),
    2483                 :         104 :              _("overflow of %qs bytes"));
    2484                 :          65 :         if (label)
    2485                 :          65 :           w->add_range (m_btm.get_table_x_for_range (invalid_after_bits),
    2486                 :         130 :                         make_warning_string (std::move (*label)),
    2487                 :          65 :                         m_invalid_style_id);
    2488                 :          65 :       }
    2489                 :             :     else
    2490                 :             :       {
    2491                 :           3 :         if (m_logger)
    2492                 :           0 :           m_logger->log ("no invalid_after_bits");
    2493                 :             :       }
    2494                 :             : 
    2495                 :          68 :     add_child (std::unique_ptr<widget> (w));
    2496                 :          68 :   }
    2497                 :             : 
    2498                 :             :   /* Subroutine of calc_req_size.
    2499                 :             :      Try to allocate surplus canvas width to table columns to make the
    2500                 :             :      per table-column canvas widths closer to being to scale.
    2501                 :             :      See e.g.:
    2502                 :             :        https://en.wikipedia.org/wiki/Fair_item_allocation
    2503                 :             :        https://en.wikipedia.org/wiki/Mathematics_of_apportionment
    2504                 :             :   */
    2505                 :          68 :   void adjust_to_scale ()
    2506                 :             :   {
    2507                 :          68 :     LOG_SCOPE (m_logger);
    2508                 :          68 :     const unsigned num_columns = m_btm.get_num_columns ();
    2509                 :          68 :     std::vector<bit_offset_t> bit_sizes (num_columns);
    2510                 :         672 :     for (unsigned table_x = 0; table_x < num_columns; table_x++)
    2511                 :             :       {
    2512                 :         604 :         access_range range_for_column (NULL, bit_range (0, 0));
    2513                 :         604 :         if (m_btm.maybe_get_access_range_for_table_x (table_x,
    2514                 :             :                                                       &range_for_column))
    2515                 :             :           {
    2516                 :         497 :             bit_size_t size_in_bits;
    2517                 :         497 :             if (!range_for_column.get_size_in_bits (&size_in_bits))
    2518                 :          73 :               size_in_bits = BITS_PER_UNIT; // arbitrary non-zero value
    2519                 :         497 :             gcc_assert (size_in_bits > 0);
    2520                 :         497 :             bit_sizes[table_x] = size_in_bits;
    2521                 :             :           }
    2522                 :             :         else
    2523                 :         107 :           bit_sizes[table_x] = 0;
    2524                 :             :       }
    2525                 :             : 
    2526                 :         734 :     while (adjust_to_scale_once (bit_sizes))
    2527                 :             :       {
    2528                 :             :       }
    2529                 :          68 :   }
    2530                 :         734 :   bool adjust_to_scale_once (const std::vector<bit_offset_t> &bit_sizes)
    2531                 :             :   {
    2532                 :         734 :     LOG_SCOPE (m_logger);
    2533                 :             : 
    2534                 :         734 :     const unsigned num_columns = m_btm.get_num_columns ();
    2535                 :             : 
    2536                 :             :     /* Find the total canvas width currently required.
    2537                 :             :        Require one extra canvas column for the right-hand border
    2538                 :             :        of the table.  */
    2539                 :         734 :     int total_width = 1;
    2540                 :        5215 :     for (unsigned table_x = 0; table_x < num_columns; table_x++)
    2541                 :             :       {
    2542                 :        4481 :         int canvas_w = m_col_widths->m_requirements[table_x];
    2543                 :        4481 :         gcc_assert (canvas_w >= 0);
    2544                 :        4481 :         total_width += canvas_w + 1;
    2545                 :             :       }
    2546                 :             : 
    2547                 :         734 :     const int max_width = param_analyzer_text_art_ideal_canvas_width;
    2548                 :         734 :     if (total_width >= max_width)
    2549                 :             :       {
    2550                 :          68 :         if (m_logger)
    2551                 :           0 :           m_logger->log ("bailing out: total_width=%i ,>= max_width (%i)\n",
    2552                 :             :                          total_width, max_width);
    2553                 :          68 :         return false;
    2554                 :             :       }
    2555                 :             : 
    2556                 :         666 :     const int fixed_point = 1024;
    2557                 :         666 :     std::vector<bit_offset_t> canvas_w_per_bit (num_columns);
    2558                 :        4543 :     for (unsigned table_x = 0; table_x < num_columns; table_x++)
    2559                 :             :       {
    2560                 :        3877 :         bit_offset_t bit_size = bit_sizes[table_x];
    2561                 :        3877 :         if (bit_size > 0)
    2562                 :        5616 :           canvas_w_per_bit[table_x]
    2563                 :        2808 :             = (m_col_widths->m_requirements[table_x] * fixed_point) / bit_size;
    2564                 :             :         else
    2565                 :        1069 :           canvas_w_per_bit[table_x] = INT_MAX;
    2566                 :             :       }
    2567                 :             : 
    2568                 :             :     /* Find the min canvas per bit, and give an extra canvas column to
    2569                 :             :        the table column that has least.  */
    2570                 :         666 :     size_t min_idx = std::distance (canvas_w_per_bit.begin (),
    2571                 :             :                                     std::min_element (canvas_w_per_bit.begin (),
    2572                 :         666 :                                                       canvas_w_per_bit.end ()));
    2573                 :         666 :     m_col_widths->m_requirements[min_idx] += 1;
    2574                 :         666 :     if (m_logger)
    2575                 :           0 :       m_logger->log ("adding 1 canvas_w to column %i\n", (int)min_idx);
    2576                 :             : 
    2577                 :         666 :     return true; // keep going
    2578                 :         734 :   }
    2579                 :             : 
    2580                 :             :   const access_operation &m_op;
    2581                 :             :   diagnostic_event_id_t m_region_creation_event_id;
    2582                 :             :   style_manager &m_sm;
    2583                 :             :   const theme &m_theme;
    2584                 :             :   logger *m_logger;
    2585                 :             :   /* In lieu of being able to throw exceptions, a flag to mark this object
    2586                 :             :      as "invalid".  */
    2587                 :             :   bool m_invalid;
    2588                 :             : 
    2589                 :             :   style::id_t m_valid_style_id;
    2590                 :             :   style::id_t m_invalid_style_id;
    2591                 :             : 
    2592                 :             :   valid_region_spatial_item m_valid_region_spatial_item;
    2593                 :             :   accessed_region_spatial_item m_accessed_region_spatial_item;
    2594                 :             :   std::unique_ptr<spatial_item> m_written_svalue_spatial_item;
    2595                 :             : 
    2596                 :             :   std::unique_ptr<boundaries> m_boundaries;
    2597                 :             : 
    2598                 :             :   bit_to_table_map m_btm;
    2599                 :             : 
    2600                 :             :   bool m_calc_req_size_called;
    2601                 :             : 
    2602                 :             :   /* Column widths shared by all x_aligned_table_widget,
    2603                 :             :      created once we know how many columns we need.  */
    2604                 :             :   std::unique_ptr<table_dimension_sizes> m_col_widths;
    2605                 :             : 
    2606                 :             :   /* All of the child x_aligned_table_widget that share
    2607                 :             :      column widths.  */
    2608                 :             :   std::vector<x_aligned_table_widget *> m_aligned_table_widgets;
    2609                 :             : 
    2610                 :             : /* Mapping from table_x to canvas_x.  */
    2611                 :             :   std::vector<int> m_col_start_x;
    2612                 :             : };
    2613                 :             : 
    2614                 :             : x_ruler
    2615                 :         136 : x_aligned_x_ruler_widget::make_x_ruler () const
    2616                 :             : {
    2617                 :         136 :   x_ruler r (x_ruler::label_dir::BELOW);
    2618                 :         448 :   for (auto& iter : m_labels)
    2619                 :             :     {
    2620                 :         312 :       canvas::range_t canvas_x_range
    2621                 :         312 :         = m_dia_impl.get_canvas_x_range (iter.m_table_x_range);
    2622                 :             :       /* Include the end-point.  */
    2623                 :         312 :       canvas_x_range.next++;
    2624                 :         312 :       r.add_label (canvas_x_range, iter.m_text.copy (), iter.m_style_id,
    2625                 :             :                    x_ruler::label_kind::TEXT_WITH_BORDER);
    2626                 :             :     }
    2627                 :         136 :   return r;
    2628                 :             : }
    2629                 :             : 
    2630                 :             : /* class direction_widget : public leaf_widget.  */
    2631                 :             : 
    2632                 :             : /* Paint arrows indicating the direction of the access (read vs write),
    2633                 :             :    but only in the X-extent corresponding to the region that's actually
    2634                 :             :    accessed.  */
    2635                 :             : 
    2636                 :             : void
    2637                 :          68 : direction_widget::paint_to_canvas (canvas &canvas)
    2638                 :             : {
    2639                 :          68 :   const access_range accessed_bits (m_dia_impl.get_op ().get_actual_bits ());
    2640                 :             : 
    2641                 :          68 :   const access_range valid_bits (m_dia_impl.get_op ().get_valid_bits ());
    2642                 :             : 
    2643                 :         672 :   for (unsigned table_x = 0; table_x < m_btm.get_num_columns (); table_x++)
    2644                 :             :     {
    2645                 :         604 :       access_range column_access_range;
    2646                 :         604 :       if (m_btm.maybe_get_access_range_for_table_x (table_x,
    2647                 :             :                                                     &column_access_range))
    2648                 :             :         {
    2649                 :             :           /* Only paint arrows in the accessed region.  */
    2650                 :         497 :           if (!accessed_bits.contains_p (column_access_range))
    2651                 :         197 :             continue;
    2652                 :             : 
    2653                 :             :           /* Are we within the valid region?  */
    2654                 :         300 :           const bool is_valid (valid_bits.contains_p (column_access_range));
    2655                 :         300 :           const style::id_t style_id
    2656                 :         300 :             = m_dia_impl.get_style_id_for_validity (is_valid);
    2657                 :         300 :           const canvas::range_t x_canvas_range
    2658                 :         600 :             = m_dia_impl.get_canvas_x_range (table::range_t (table_x,
    2659                 :         300 :                                                              table_x + 1));
    2660                 :         300 :           const int canvas_x = x_canvas_range.get_midpoint ();
    2661                 :         300 :           m_dia_impl.get_theme ().paint_y_arrow
    2662                 :         300 :             (canvas,
    2663                 :             :              canvas_x,
    2664                 :             :              canvas::range_t (get_y_range ()),
    2665                 :         300 :              (m_dia_impl.get_op ().m_dir == DIR_READ
    2666                 :         300 :               ? theme::y_arrow_dir::UP
    2667                 :             :               : theme::y_arrow_dir::DOWN),
    2668                 :             :              style_id);
    2669                 :             :         }
    2670                 :             :     }
    2671                 :          68 : }
    2672                 :             : 
    2673                 :             : /* class access_diagram : public text_art::wrapper_widget.  */
    2674                 :             : 
    2675                 :             : /* To hide the implementation details, this is merely a wrapper around
    2676                 :             :    an access_diagram_impl.  */
    2677                 :             : 
    2678                 :          73 : access_diagram::access_diagram (const access_operation &op,
    2679                 :             :                                 diagnostic_event_id_t region_creation_event_id,
    2680                 :             :                                 style_manager &sm,
    2681                 :             :                                 const theme &theme,
    2682                 :          73 :                                 logger *logger)
    2683                 :          73 : : wrapper_widget (make_unique <access_diagram_impl> (op,
    2684                 :             :                                                      region_creation_event_id,
    2685                 :             :                                                      sm,
    2686                 :             :                                                      theme,
    2687                 :          73 :                                                      logger))
    2688                 :             : {
    2689                 :          73 : }
    2690                 :             : 
    2691                 :             : #if CHECKING_P
    2692                 :             : 
    2693                 :             : namespace selftest {
    2694                 :             : 
    2695                 :             : /* Implementation detail of ASSERT_EQ_TYPELESS_INTEGER.  */
    2696                 :             : 
    2697                 :             : static void
    2698                 :           8 : assert_eq_typeless_integer (const location &loc,
    2699                 :             :                             const svalue *sval,
    2700                 :             :                             int expected_int_val)
    2701                 :             : {
    2702                 :           8 :   ASSERT_NE_AT (loc, sval, nullptr);
    2703                 :           8 :   ASSERT_EQ_AT (loc, sval->get_kind (), SK_CONSTANT);
    2704                 :           8 :   ASSERT_EQ_AT (loc,
    2705                 :             :                 wi::to_offset (sval->maybe_get_constant ()),
    2706                 :             :                 expected_int_val);
    2707                 :           8 :   ASSERT_EQ_AT (loc, sval->get_type (), NULL_TREE);
    2708                 :           8 : }
    2709                 :             : 
    2710                 :             : /* Assert that SVAL is a constant_svalue equal to EXPECTED_INT_VAL,
    2711                 :             :    with NULL_TREE as its type.  */
    2712                 :             : 
    2713                 :             : #define ASSERT_EQ_TYPELESS_INTEGER(SVAL, EXPECTED_INT_VAL) \
    2714                 :             :   SELFTEST_BEGIN_STMT                                                  \
    2715                 :             :   assert_eq_typeless_integer ((SELFTEST_LOCATION),                     \
    2716                 :             :                               (SVAL),                                  \
    2717                 :             :                               (EXPECTED_INT_VAL));                     \
    2718                 :             :   SELFTEST_END_STMT
    2719                 :             : 
    2720                 :             : 
    2721                 :             : /* Various tests of bit_size_expr::maybe_get_as_bytes.  */
    2722                 :             : 
    2723                 :             : static void
    2724                 :           4 : test_bit_size_expr_to_bytes ()
    2725                 :             : {
    2726                 :           4 :   region_model_manager mgr;
    2727                 :             : 
    2728                 :             :   /* 40 bits: should be 5 bytes.  */
    2729                 :           4 :   {
    2730                 :           4 :     bit_size_expr num_bits (*mgr.get_or_create_int_cst (NULL_TREE, 40));
    2731                 :           4 :     const svalue *as_bytes = num_bits.maybe_get_as_bytes (mgr);
    2732                 :           4 :     ASSERT_EQ_TYPELESS_INTEGER (as_bytes, 5);
    2733                 :             :   }
    2734                 :             : 
    2735                 :             :   /* 41 bits: should not convert to bytes.  */
    2736                 :           4 :   {
    2737                 :           4 :     bit_size_expr num_bits (*mgr.get_or_create_int_cst (NULL_TREE, 41));
    2738                 :           4 :     const svalue *as_bytes = num_bits.maybe_get_as_bytes (mgr);
    2739                 :           4 :     ASSERT_EQ (as_bytes, nullptr);
    2740                 :             :   }
    2741                 :             : 
    2742                 :           4 :   tree n = build_global_decl ("n", size_type_node);
    2743                 :             : 
    2744                 :           4 :   const svalue *init_n
    2745                 :           4 :     = mgr.get_or_create_initial_value (mgr.get_region_for_global (n));
    2746                 :             : 
    2747                 :           4 :   const svalue *n_times_8
    2748                 :           4 :     = mgr.get_or_create_binop (NULL_TREE, MULT_EXPR,
    2749                 :             :                                init_n,
    2750                 :           4 :                                mgr.get_or_create_int_cst (NULL_TREE, 8));
    2751                 :             : 
    2752                 :             :   /* (n * 8) bits should be n bytes */
    2753                 :           4 :   {
    2754                 :           4 :     bit_size_expr num_bits (*n_times_8);
    2755                 :           4 :     const svalue *as_bytes = num_bits.maybe_get_as_bytes (mgr);
    2756                 :           4 :     ASSERT_EQ (as_bytes, mgr.get_or_create_cast (NULL_TREE, init_n));
    2757                 :             :   }
    2758                 :             : 
    2759                 :             :   /* (n * 8) + 16 bits should be n + 2 bytes */
    2760                 :           4 :   {
    2761                 :           4 :     bit_size_expr num_bits
    2762                 :           4 :       (*mgr.get_or_create_binop (NULL_TREE, PLUS_EXPR,
    2763                 :             :                                  n_times_8,
    2764                 :           4 :                                  mgr.get_or_create_int_cst (NULL_TREE, 16)));
    2765                 :           4 :     const svalue *as_bytes = num_bits.maybe_get_as_bytes (mgr);
    2766                 :           4 :     ASSERT_EQ (as_bytes->get_kind (), SK_BINOP);
    2767                 :           4 :     const binop_svalue *binop = as_bytes->dyn_cast_binop_svalue ();
    2768                 :           4 :     ASSERT_EQ (binop->get_op (), PLUS_EXPR);
    2769                 :           4 :     ASSERT_EQ (binop->get_arg0 (), mgr.get_or_create_cast (NULL_TREE, init_n));
    2770                 :           4 :     ASSERT_EQ_TYPELESS_INTEGER (binop->get_arg1 (), 2);
    2771                 :             :   }
    2772                 :           4 : }
    2773                 :             : 
    2774                 :             : /* Run all of the selftests within this file.  */
    2775                 :             : 
    2776                 :             : void
    2777                 :           4 : analyzer_access_diagram_cc_tests ()
    2778                 :             : {
    2779                 :           4 :   test_bit_size_expr_to_bytes ();
    2780                 :           4 : }
    2781                 :             : 
    2782                 :             : } // namespace selftest
    2783                 :             : 
    2784                 :             : #endif /* CHECKING_P */
    2785                 :             : 
    2786                 :             : } // namespace ana
    2787                 :             : 
    2788                 :             : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.