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