1*6881a400Schristos /* Copyright (C) 2020-2023 Free Software Foundation, Inc. 2*6881a400Schristos 3*6881a400Schristos This file is part of GDB. 4*6881a400Schristos 5*6881a400Schristos This program is free software; you can redistribute it and/or modify 6*6881a400Schristos it under the terms of the GNU General Public License as published by 7*6881a400Schristos the Free Software Foundation; either version 3 of the License, or 8*6881a400Schristos (at your option) any later version. 9*6881a400Schristos 10*6881a400Schristos This program is distributed in the hope that it will be useful, 11*6881a400Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 12*6881a400Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*6881a400Schristos GNU General Public License for more details. 14*6881a400Schristos 15*6881a400Schristos You should have received a copy of the GNU General Public License 16*6881a400Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17*6881a400Schristos 18*6881a400Schristos /* Support classes to wrap up the process of iterating over a 19*6881a400Schristos multi-dimensional Fortran array. */ 20*6881a400Schristos 21*6881a400Schristos #ifndef F_ARRAY_WALKER_H 22*6881a400Schristos #define F_ARRAY_WALKER_H 23*6881a400Schristos 24*6881a400Schristos #include "defs.h" 25*6881a400Schristos #include "gdbtypes.h" 26*6881a400Schristos #include "f-lang.h" 27*6881a400Schristos 28*6881a400Schristos /* Class for calculating the byte offset for elements within a single 29*6881a400Schristos dimension of a Fortran array. */ 30*6881a400Schristos class fortran_array_offset_calculator 31*6881a400Schristos { 32*6881a400Schristos public: 33*6881a400Schristos /* Create a new offset calculator for TYPE, which is either an array or a 34*6881a400Schristos string. */ 35*6881a400Schristos explicit fortran_array_offset_calculator (struct type *type) 36*6881a400Schristos { 37*6881a400Schristos /* Validate the type. */ 38*6881a400Schristos type = check_typedef (type); 39*6881a400Schristos if (type->code () != TYPE_CODE_ARRAY 40*6881a400Schristos && (type->code () != TYPE_CODE_STRING)) 41*6881a400Schristos error (_("can only compute offsets for arrays and strings")); 42*6881a400Schristos 43*6881a400Schristos /* Get the range, and extract the bounds. */ 44*6881a400Schristos struct type *range_type = type->index_type (); 45*6881a400Schristos if (!get_discrete_bounds (range_type, &m_lowerbound, &m_upperbound)) 46*6881a400Schristos error ("unable to read array bounds"); 47*6881a400Schristos 48*6881a400Schristos /* Figure out the stride for this array. */ 49*6881a400Schristos struct type *elt_type = check_typedef (type->target_type ()); 50*6881a400Schristos m_stride = type->index_type ()->bounds ()->bit_stride (); 51*6881a400Schristos if (m_stride == 0) 52*6881a400Schristos m_stride = type_length_units (elt_type); 53*6881a400Schristos else 54*6881a400Schristos { 55*6881a400Schristos int unit_size 56*6881a400Schristos = gdbarch_addressable_memory_unit_size (elt_type->arch ()); 57*6881a400Schristos m_stride /= (unit_size * 8); 58*6881a400Schristos } 59*6881a400Schristos }; 60*6881a400Schristos 61*6881a400Schristos /* Get the byte offset for element INDEX within the type we are working 62*6881a400Schristos on. There is no bounds checking done on INDEX. If the stride is 63*6881a400Schristos negative then we still assume that the base address (for the array 64*6881a400Schristos object) points to the element with the lowest memory address, we then 65*6881a400Schristos calculate an offset assuming that index 0 will be the element at the 66*6881a400Schristos highest address, index 1 the next highest, and so on. This is not 67*6881a400Schristos quite how Fortran works in reality; in reality the base address of 68*6881a400Schristos the object would point at the element with the highest address, and 69*6881a400Schristos we would index backwards from there in the "normal" way, however, 70*6881a400Schristos GDB's current value contents model doesn't support having the base 71*6881a400Schristos address be near to the end of the value contents, so we currently 72*6881a400Schristos adjust the base address of Fortran arrays with negative strides so 73*6881a400Schristos their base address points at the lowest memory address. This code 74*6881a400Schristos here is part of working around this weirdness. */ 75*6881a400Schristos LONGEST index_offset (LONGEST index) 76*6881a400Schristos { 77*6881a400Schristos LONGEST offset; 78*6881a400Schristos if (m_stride < 0) 79*6881a400Schristos offset = std::abs (m_stride) * (m_upperbound - index); 80*6881a400Schristos else 81*6881a400Schristos offset = std::abs (m_stride) * (index - m_lowerbound); 82*6881a400Schristos return offset; 83*6881a400Schristos } 84*6881a400Schristos 85*6881a400Schristos private: 86*6881a400Schristos 87*6881a400Schristos /* The stride for the type we are working with. */ 88*6881a400Schristos LONGEST m_stride; 89*6881a400Schristos 90*6881a400Schristos /* The upper bound for the type we are working with. */ 91*6881a400Schristos LONGEST m_upperbound; 92*6881a400Schristos 93*6881a400Schristos /* The lower bound for the type we are working with. */ 94*6881a400Schristos LONGEST m_lowerbound; 95*6881a400Schristos }; 96*6881a400Schristos 97*6881a400Schristos /* A base class used by fortran_array_walker. There's no virtual methods 98*6881a400Schristos here, sub-classes should just override the functions they want in order 99*6881a400Schristos to specialise the behaviour to their needs. The functionality 100*6881a400Schristos provided in these default implementations will visit every array 101*6881a400Schristos element, but do nothing for each element. */ 102*6881a400Schristos 103*6881a400Schristos struct fortran_array_walker_base_impl 104*6881a400Schristos { 105*6881a400Schristos /* Called when iterating between the lower and upper bounds of each 106*6881a400Schristos dimension of the array. Return true if GDB should continue iterating, 107*6881a400Schristos otherwise, return false. 108*6881a400Schristos 109*6881a400Schristos SHOULD_CONTINUE indicates if GDB is going to stop anyway, and should 110*6881a400Schristos be taken into consideration when deciding what to return. If 111*6881a400Schristos SHOULD_CONTINUE is false then this function must also return false, 112*6881a400Schristos the function is still called though in case extra work needs to be 113*6881a400Schristos done as part of the stopping process. */ 114*6881a400Schristos bool continue_walking (bool should_continue) 115*6881a400Schristos { return should_continue; } 116*6881a400Schristos 117*6881a400Schristos /* Called when GDB starts iterating over a dimension of the array. The 118*6881a400Schristos argument INDEX_TYPE is the type of the index used to address elements 119*6881a400Schristos in the dimension, NELTS holds the number of the elements there, and 120*6881a400Schristos INNER_P is true for the inner most dimension (the dimension containing 121*6881a400Schristos the actual elements of the array), and false for more outer dimensions. 122*6881a400Schristos For a concrete example of how this function is called see the comment 123*6881a400Schristos on process_element below. */ 124*6881a400Schristos void start_dimension (struct type *index_type, LONGEST nelts, bool inner_p) 125*6881a400Schristos { /* Nothing. */ } 126*6881a400Schristos 127*6881a400Schristos /* Called when GDB finishes iterating over a dimension of the array. The 128*6881a400Schristos argument INNER_P is true for the inner most dimension (the dimension 129*6881a400Schristos containing the actual elements of the array), and false for more outer 130*6881a400Schristos dimensions. LAST_P is true for the last call at a particular 131*6881a400Schristos dimension. For a concrete example of how this function is called 132*6881a400Schristos see the comment on process_element below. */ 133*6881a400Schristos void finish_dimension (bool inner_p, bool last_p) 134*6881a400Schristos { /* Nothing. */ } 135*6881a400Schristos 136*6881a400Schristos /* Called when processing dimensions of the array other than the 137*6881a400Schristos innermost one. WALK_1 is the walker to normally call, ELT_TYPE is 138*6881a400Schristos the type of the element being extracted, and ELT_OFF is the offset 139*6881a400Schristos of the element from the start of array being walked. INDEX is the 140*6881a400Schristos value of the index the current element is at in the upper dimension. 141*6881a400Schristos Finally LAST_P is true only when this is the last element that will 142*6881a400Schristos be processed in this dimension. */ 143*6881a400Schristos void process_dimension (gdb::function_view<void (struct type *, 144*6881a400Schristos int, bool)> walk_1, 145*6881a400Schristos struct type *elt_type, LONGEST elt_off, 146*6881a400Schristos LONGEST index, bool last_p) 147*6881a400Schristos { 148*6881a400Schristos walk_1 (elt_type, elt_off, last_p); 149*6881a400Schristos } 150*6881a400Schristos 151*6881a400Schristos /* Called when processing the inner most dimension of the array, for 152*6881a400Schristos every element in the array. ELT_TYPE is the type of the element being 153*6881a400Schristos extracted, and ELT_OFF is the offset of the element from the start of 154*6881a400Schristos array being walked. INDEX is the value of the index the current 155*6881a400Schristos element is at in the upper dimension. Finally LAST_P is true only 156*6881a400Schristos when this is the last element that will be processed in this dimension. 157*6881a400Schristos 158*6881a400Schristos Given this two dimensional array ((1, 2) (3, 4) (5, 6)), the calls to 159*6881a400Schristos start_dimension, process_element, and finish_dimension look like this: 160*6881a400Schristos 161*6881a400Schristos start_dimension (INDEX_TYPE, 3, false); 162*6881a400Schristos start_dimension (INDEX_TYPE, 2, true); 163*6881a400Schristos process_element (TYPE, OFFSET, false); 164*6881a400Schristos process_element (TYPE, OFFSET, true); 165*6881a400Schristos finish_dimension (true, false); 166*6881a400Schristos start_dimension (INDEX_TYPE, 2, true); 167*6881a400Schristos process_element (TYPE, OFFSET, false); 168*6881a400Schristos process_element (TYPE, OFFSET, true); 169*6881a400Schristos finish_dimension (true, true); 170*6881a400Schristos start_dimension (INDEX_TYPE, 2, true); 171*6881a400Schristos process_element (TYPE, OFFSET, false); 172*6881a400Schristos process_element (TYPE, OFFSET, true); 173*6881a400Schristos finish_dimension (true, true); 174*6881a400Schristos finish_dimension (false, true); */ 175*6881a400Schristos void process_element (struct type *elt_type, LONGEST elt_off, 176*6881a400Schristos LONGEST index, bool last_p) 177*6881a400Schristos { /* Nothing. */ } 178*6881a400Schristos }; 179*6881a400Schristos 180*6881a400Schristos /* A class to wrap up the process of iterating over a multi-dimensional 181*6881a400Schristos Fortran array. IMPL is used to specialise what happens as we walk over 182*6881a400Schristos the array. See class FORTRAN_ARRAY_WALKER_BASE_IMPL (above) for the 183*6881a400Schristos methods than can be used to customise the array walk. */ 184*6881a400Schristos template<typename Impl> 185*6881a400Schristos class fortran_array_walker 186*6881a400Schristos { 187*6881a400Schristos /* Ensure that Impl is derived from the required base class. This just 188*6881a400Schristos ensures that all of the required API methods are available and have a 189*6881a400Schristos sensible default implementation. */ 190*6881a400Schristos gdb_static_assert ((std::is_base_of<fortran_array_walker_base_impl,Impl>::value)); 191*6881a400Schristos 192*6881a400Schristos public: 193*6881a400Schristos /* Create a new array walker. TYPE is the type of the array being walked 194*6881a400Schristos over, and ADDRESS is the base address for the object of TYPE in 195*6881a400Schristos memory. All other arguments are forwarded to the constructor of the 196*6881a400Schristos template parameter class IMPL. */ 197*6881a400Schristos template <typename ...Args> 198*6881a400Schristos fortran_array_walker (struct type *type, CORE_ADDR address, 199*6881a400Schristos Args... args) 200*6881a400Schristos : m_type (type), 201*6881a400Schristos m_address (address), 202*6881a400Schristos m_impl (type, address, args...), 203*6881a400Schristos m_ndimensions (calc_f77_array_dims (m_type)), 204*6881a400Schristos m_nss (0) 205*6881a400Schristos { /* Nothing. */ } 206*6881a400Schristos 207*6881a400Schristos /* Walk the array. */ 208*6881a400Schristos void 209*6881a400Schristos walk () 210*6881a400Schristos { 211*6881a400Schristos walk_1 (m_type, 0, false); 212*6881a400Schristos } 213*6881a400Schristos 214*6881a400Schristos private: 215*6881a400Schristos /* The core of the array walking algorithm. TYPE is the type of 216*6881a400Schristos the current dimension being processed and OFFSET is the offset 217*6881a400Schristos (in bytes) for the start of this dimension. */ 218*6881a400Schristos void 219*6881a400Schristos walk_1 (struct type *type, int offset, bool last_p) 220*6881a400Schristos { 221*6881a400Schristos /* Extract the range, and get lower and upper bounds. */ 222*6881a400Schristos struct type *range_type = check_typedef (type)->index_type (); 223*6881a400Schristos LONGEST lowerbound, upperbound; 224*6881a400Schristos if (!get_discrete_bounds (range_type, &lowerbound, &upperbound)) 225*6881a400Schristos error ("failed to get range bounds"); 226*6881a400Schristos 227*6881a400Schristos /* CALC is used to calculate the offsets for each element in this 228*6881a400Schristos dimension. */ 229*6881a400Schristos fortran_array_offset_calculator calc (type); 230*6881a400Schristos 231*6881a400Schristos m_nss++; 232*6881a400Schristos gdb_assert (range_type->code () == TYPE_CODE_RANGE); 233*6881a400Schristos m_impl.start_dimension (range_type->target_type (), 234*6881a400Schristos upperbound - lowerbound + 1, 235*6881a400Schristos m_nss == m_ndimensions); 236*6881a400Schristos 237*6881a400Schristos if (m_nss != m_ndimensions) 238*6881a400Schristos { 239*6881a400Schristos struct type *subarray_type = check_typedef (type)->target_type (); 240*6881a400Schristos 241*6881a400Schristos /* For dimensions other than the inner most, walk each element and 242*6881a400Schristos recurse while peeling off one more dimension of the array. */ 243*6881a400Schristos for (LONGEST i = lowerbound; 244*6881a400Schristos m_impl.continue_walking (i < upperbound + 1); 245*6881a400Schristos i++) 246*6881a400Schristos { 247*6881a400Schristos /* Use the index and the stride to work out a new offset. */ 248*6881a400Schristos LONGEST new_offset = offset + calc.index_offset (i); 249*6881a400Schristos 250*6881a400Schristos /* Now print the lower dimension. */ 251*6881a400Schristos m_impl.process_dimension 252*6881a400Schristos ([this] (struct type *w_type, int w_offset, bool w_last_p) -> void 253*6881a400Schristos { 254*6881a400Schristos this->walk_1 (w_type, w_offset, w_last_p); 255*6881a400Schristos }, 256*6881a400Schristos subarray_type, new_offset, i, i == upperbound); 257*6881a400Schristos } 258*6881a400Schristos } 259*6881a400Schristos else 260*6881a400Schristos { 261*6881a400Schristos struct type *elt_type = check_typedef (type)->target_type (); 262*6881a400Schristos 263*6881a400Schristos /* For the inner most dimension of the array, process each element 264*6881a400Schristos within this dimension. */ 265*6881a400Schristos for (LONGEST i = lowerbound; 266*6881a400Schristos m_impl.continue_walking (i < upperbound + 1); 267*6881a400Schristos i++) 268*6881a400Schristos { 269*6881a400Schristos LONGEST elt_off = offset + calc.index_offset (i); 270*6881a400Schristos 271*6881a400Schristos if (is_dynamic_type (elt_type)) 272*6881a400Schristos { 273*6881a400Schristos CORE_ADDR e_address = m_address + elt_off; 274*6881a400Schristos elt_type = resolve_dynamic_type (elt_type, {}, e_address); 275*6881a400Schristos } 276*6881a400Schristos 277*6881a400Schristos m_impl.process_element (elt_type, elt_off, i, i == upperbound); 278*6881a400Schristos } 279*6881a400Schristos } 280*6881a400Schristos 281*6881a400Schristos m_impl.finish_dimension (m_nss == m_ndimensions, last_p || m_nss == 1); 282*6881a400Schristos m_nss--; 283*6881a400Schristos } 284*6881a400Schristos 285*6881a400Schristos /* The array type being processed. */ 286*6881a400Schristos struct type *m_type; 287*6881a400Schristos 288*6881a400Schristos /* The address in target memory for the object of M_TYPE being 289*6881a400Schristos processed. This is required in order to resolve dynamic types. */ 290*6881a400Schristos CORE_ADDR m_address; 291*6881a400Schristos 292*6881a400Schristos /* An instance of the template specialisation class. */ 293*6881a400Schristos Impl m_impl; 294*6881a400Schristos 295*6881a400Schristos /* The total number of dimensions in M_TYPE. */ 296*6881a400Schristos int m_ndimensions; 297*6881a400Schristos 298*6881a400Schristos /* The current dimension number being processed. */ 299*6881a400Schristos int m_nss; 300*6881a400Schristos }; 301*6881a400Schristos 302*6881a400Schristos #endif /* F_ARRAY_WALKER_H */ 303