Home | History | Annotate | Line # | Download | only in gdb.base
      1 # Copyright 2022-2024 Free Software Foundation, Inc.
      2 
      3 # This program is free software; you can redistribute it and/or modify
      4 # it under the terms of the GNU General Public License as published by
      5 # the Free Software Foundation; either version 3 of the License, or
      6 # (at your option) any later version.
      7 #
      8 # This program is distributed in the hope that it will be useful,
      9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 # GNU General Public License for more details.
     12 #
     13 # You should have received a copy of the GNU General Public License
     14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 
     16 # Format hex value VAL for language LANG.
     17 
     18 proc hex_for_lang { lang val } {
     19     set neg_p [regexp ^- $val]
     20     set val [regsub ^-?0x $val ""]
     21     if { $lang == "modula-2" } {
     22        set val 0[string toupper $val]H
     23     } else {
     24        set val 0x$val
     25     }
     26     if { $neg_p } {
     27 	return -$val
     28     } else {
     29 	return $val
     30     }
     31 }
     32 
     33 # Determine whether N fits in type with TYPE_BITS and TYPE_SIGNEDNESS.
     34 
     35 proc fits_in_type { n type_bits type_signedness } {
     36     if { $type_signedness == "s" } {
     37 	set type_signed_p 1
     38     } elseif { $type_signedness == "u" } {
     39 	set type_signed_p 0
     40     } else {
     41 	error "unreachable"
     42     }
     43 
     44     if { $n < 0 && !$type_signed_p } {
     45 	# Can't fit a negative number in an unsigned type.
     46 	return 0
     47     }
     48 
     49     if { $n < 0} {
     50 	set n_sign -1
     51 	set n [expr -$n]
     52     } else {
     53 	set n_sign 1
     54     }
     55 
     56     set smax [expr 1 << ($type_bits - 1)];
     57     if  { $n_sign == -1 } {
     58 	# Negative number, signed type.
     59 	return [expr ($n <= $smax)]
     60     } elseif { $n_sign == 1 && $type_signed_p } {
     61 	# Positive number, signed type.
     62 	return [expr ($n < $smax)]
     63     } elseif { $n_sign == 1 && !$type_signed_p } {
     64 	# Positive number, unsigned type.
     65 	return [expr ($n >> $type_bits) == 0]
     66     } else {
     67 	error "unreachable"
     68     }
     69 }
     70 
     71 # Return 1 if LANG is a c-like language, in the sense that it uses the same
     72 # parser.
     73 
     74 proc c_like { lang } {
     75     set res 0
     76     switch $lang {
     77 	c
     78 	- c++
     79 	- asm
     80 	- objective-c
     81 	- opencl
     82 	- minimal {set res 1}
     83     }
     84     return $res
     85 }
     86 
     87 # Parse number N for LANG, and return a list of expected type and value.
     88 
     89 proc parse_number { lang n } {
     90     global re_overflow
     91 
     92     set hex_p [regexp ^-?0x $n]
     93 
     94     global hex decimal
     95     if { $hex_p } {
     96 	set any $hex
     97     } else {
     98 	set any $decimal
     99     }
    100 
    101     global sizeof_long_long sizeof_long sizeof_int
    102     set long_long_bits [expr $sizeof_long_long * 8]
    103     set long_bits [expr $sizeof_long * 8]
    104     set int_bits [expr $sizeof_int * 8]
    105 
    106     if { $lang == "rust" } {
    107 	if { [fits_in_type $n 32 s] } {
    108 	    return [list "i32" $n]
    109 	} elseif { [fits_in_type $n 64 s] } {
    110 	    return [list "i64" $n]
    111 	} elseif { [fits_in_type $n 128 u] } {
    112 	    return [list "i128" $n]
    113 	} else {
    114 	    # Overflow.
    115 	    return [list $re_overflow $re_overflow]
    116 	}
    117     } elseif { $lang == "d" } {
    118 	if { [fits_in_type $n 32 s] } {
    119 	    return [list int $n]
    120 	} elseif { [fits_in_type $n 32 u] } {
    121 	    if { $hex_p } {
    122 		return [list uint $n]
    123 	    } else {
    124 		return [list long $n]
    125 	    }
    126 	} elseif { [fits_in_type $n 64 s] } {
    127 	    return [list long $n]
    128 	} elseif { [fits_in_type $n 64 u] } {
    129 	    return [list ulong $n]
    130 	} else {
    131 	    # Overflow.
    132 	    return [list $re_overflow $re_overflow]
    133 	}
    134     } elseif { $lang == "ada" } {
    135 	if { [fits_in_type $n $int_bits s] } {
    136 	    return [list "<$sizeof_int-byte integer>" $n]
    137 	} elseif { [fits_in_type $n $long_bits s] } {
    138 	    return [list "<$sizeof_long-byte integer>" $n]
    139 	} elseif { [fits_in_type $n $long_bits u] } {
    140 	    return [list "<$sizeof_long-byte integer>" $n]
    141 	} elseif { [fits_in_type $n $long_long_bits s] } {
    142 	    return [list "<$sizeof_long_long-byte integer>" $n]
    143 	} elseif { [fits_in_type $n $long_long_bits u] } {
    144 	    # Note: Interprets ULLONG_MAX as -1.
    145 	    return [list "<$sizeof_long_long-byte integer>" $n]
    146 	} elseif { [fits_in_type $n 128 u] } {
    147 	    return [list "<16-byte integer>" $n]
    148 	} else {
    149 	    # Overflow.
    150 	    return [list $re_overflow $re_overflow]
    151 	}
    152     } elseif { $lang == "modula-2" } {
    153 	if { [string equal $n -0] } {
    154 	    # Note: 0 is CARDINAL, but -0 is an INTEGER.
    155 	    return [list "INTEGER" 0]
    156 	}
    157 	if { $n < 0 && [fits_in_type $n $int_bits s] } {
    158 	    return [list "INTEGER" $n]
    159 	} elseif { [fits_in_type $n $int_bits u] } {
    160 	    return [list "CARDINAL" $n]
    161 	} else {
    162 	    # Overflow.
    163 	    return [list $re_overflow $re_overflow]
    164 	}
    165     } elseif { $lang == "fortran" } {
    166 	if { [fits_in_type $n $int_bits s] } {
    167 	    return [list int $n]
    168 	} elseif { [fits_in_type $n $int_bits u] } {
    169 	    return [list "unsigned int" $n]
    170 	} elseif { [fits_in_type $n $long_bits s] } {
    171 	    return [list long $n]
    172 	} elseif { [fits_in_type $n $long_bits u] } {
    173 	    return [list "unsigned long" $n]
    174 	} else {
    175 	    # Overflow.
    176 	    return [list $re_overflow $re_overflow]
    177 	}
    178     } else {
    179 	if { [c_like $lang] } {
    180 	    if { $hex_p } {
    181 		# C Hex.
    182 		set have_unsigned 1
    183 	    } else {
    184 		# C Decimal.  Unsigned not allowed according.
    185 		if { [fits_in_type $n $long_long_bits s] } {
    186 		    # Fits in largest signed type.
    187 		    set have_unsigned 0
    188 		} else {
    189 		    # Doesn't fit in largest signed type, so ill-formed, but
    190 		    # allow unsigned as a convenience, as compilers do (though
    191 		    # with a warning).
    192 		    set have_unsigned 1
    193 		}
    194 	    }
    195 	} else {
    196 	    # Non-C.
    197 	    set have_unsigned 1
    198 	}
    199 
    200 	if { [fits_in_type $n $int_bits s] } {
    201 	    return [list int $n]
    202 	} elseif { $have_unsigned && [fits_in_type $n $int_bits u] } {
    203 	    return [list "unsigned int" $n]
    204 	} elseif { [fits_in_type $n $long_bits s] } {
    205 	    return [list long $n]
    206 	} elseif { $have_unsigned && [fits_in_type $n $long_bits u] } {
    207 	    return [list "unsigned long" $n]
    208 	} elseif { [fits_in_type $n $long_long_bits s] } {
    209 	    return [list "long long" $n]
    210 	} elseif { $have_unsigned && [fits_in_type $n $long_long_bits u] } {
    211 	    return [list "unsigned long long" $n]
    212 	} else {
    213 	    # Overflow.
    214 	    return [list $re_overflow $re_overflow]
    215 	}
    216     }
    217 
    218     error "unreachable"
    219 }
    220 
    221 # Test parsing numbers.  Several language parsers had the same bug
    222 # around parsing large 64-bit numbers, hitting undefined behavior, and
    223 # thus crashing a GDB built with UBSan.  This testcase goes over all
    224 # languages exercising printing the max 64-bit number, making sure
    225 # that GDB doesn't crash.  ARCH is the architecture to test with.
    226 
    227 proc test_parse_numbers {arch} {
    228     global full_arch_testing
    229     global tested_archs
    230     global verbose
    231 
    232     set arch_re [string_to_regexp $arch]
    233     gdb_test "set architecture $arch" "The target architecture is set to \"$arch_re\"."
    234 
    235     gdb_test_no_output "set language c"
    236 
    237     # Types have different sizes depending on the architecture.
    238     # Figure out type sizes before matching patterns in the upcoming
    239     # tests.
    240 
    241     global sizeof_long_long sizeof_long sizeof_int sizeof_short
    242     set sizeof_long_long [get_sizeof "long long" -1]
    243     set sizeof_long [get_sizeof "long" -1]
    244     set sizeof_int [get_sizeof "int" -1]
    245     set sizeof_short [get_sizeof "short" -1]
    246 
    247     if { ! $full_arch_testing } {
    248 	set arch_id \
    249 	    [list $sizeof_long_long $sizeof_long $sizeof_long $sizeof_int \
    250 		 $sizeof_short]
    251 	if { [lsearch $tested_archs $arch_id] == -1 } {
    252 	    lappend tested_archs $arch_id
    253 	} else {
    254 	    return
    255 	}
    256     }
    257 
    258     foreach_with_prefix lang $::all_languages {
    259 	if { $lang == "unknown" } {
    260 	    # Tested outside $supported_archs loop.
    261 	    continue
    262 	} elseif { $lang == "auto" || $lang == "local" } {
    263 	    # Avoid duplicate testing.
    264 	    continue
    265 	}
    266 
    267 	gdb_test_no_output "set language $lang"
    268 
    269 	global re_overflow
    270 	if { $lang == "modula-2" || $lang == "fortran" } {
    271 	    set re_overflow "Overflow on numeric constant\\."
    272 	} elseif { $lang == "ada" } {
    273 	    set re_overflow "Integer literal out of range"
    274 	} elseif { $lang == "rust" } {
    275 	    set re_overflow "Integer literal is too large"
    276 	} else {
    277 	    set re_overflow "Numeric constant too large\\."
    278 	}
    279 
    280 	set basevals {
    281 	    0xffffffffffffffff
    282 	    0x7fffffffffffffff
    283 	    0xffffffff
    284 	    0x7fffffff
    285 	    0xffff
    286 	    0x7fff
    287 	    0xff
    288 	    0x7f
    289 	    0x0
    290 	}
    291 
    292 	if { $lang == "modula-2" } {
    293 	    # Modula-2 is the only language that changes the type of an
    294 	    # integral literal based on whether it's prefixed with "-",
    295 	    # so test both scenarios.
    296 	    set prefixes { "" "-" }
    297 	} else {
    298 	    # For all the other languages, we'd just be testing the
    299 	    # parsing twice, so just test the basic scenario of no prefix.
    300 	    set prefixes { "" }
    301 	}
    302 
    303 	foreach_with_prefix prefix $prefixes {
    304 	    foreach baseval $basevals {
    305 		foreach offset { -2 -1 0 1 2 } {
    306 		    set dec_val [expr $baseval + $offset]
    307 		    set hex_val [format "0x%llx" $dec_val]
    308 		    if { $dec_val < 0 } {
    309 			continue
    310 		    }
    311 
    312 		    set dec_val $prefix$dec_val
    313 		    lassign [parse_number $lang $dec_val] type out
    314 		    if { $verbose >= 1 } { verbose -log "EXPECTED: $out" 2 }
    315 		    if { $prefix == "" } {
    316 			gdb_test "p/u $dec_val" "$out"
    317 		    } else {
    318 			gdb_test "p/d $dec_val" "$out"
    319 		    }
    320 		    if { $verbose >= 1 } { verbose -log "EXPECTED: $type" 2 }
    321 		    gdb_test "ptype $dec_val" "$type"
    322 
    323 		    if { $prefix == "-" } {
    324 			# Printing with /x below means negative numbers are
    325 			# converted to unsigned representation.  We could
    326 			# support this by updating the expected patterns.
    327 			# Possibly, we could print with /u and /d instead of
    328 			# /x here as well (which would also require updating
    329 			# expected patterns).
    330 			# For now, this doesn't seem worth the trouble,
    331 			# so skip.
    332 			continue
    333 		    }
    334 
    335 		    set hex_val $prefix$hex_val
    336 		    lassign [parse_number $lang $hex_val] type out
    337 		    set hex_val [hex_for_lang $lang $hex_val]
    338 		    if { $verbose >= 1 } { verbose -log "EXPECTED: $out" 2 }
    339 		    gdb_test "p/x $hex_val" "$out"
    340 		    if { $verbose >= 1 } { verbose -log "EXPECTED: $type" 2 }
    341 		    gdb_test "ptype $hex_val" "$type"
    342 		}
    343 	    }
    344 	}
    345     }
    346 }
    347 
    348 clean_restart
    349 
    350 set supported_archs [get_set_option_choices "set architecture"]
    351 # There should be at least one more than "auto".
    352 gdb_assert {[llength $supported_archs] > 1} "at least one architecture"
    353 
    354 set all_languages [get_set_option_choices "set language"]
    355 
    356 gdb_test_no_output "set language unknown"
    357 gdb_test "p/x 0" \
    358 	"expression parsing not implemented for language \"Unknown\""
    359 
    360 # If 1, test each arch.  If 0, test one arch for each sizeof
    361 # short/int/long/longlong configuration.
    362 # For a build with --enable-targets=all, full_arch_testing == 0 takes 15s,
    363 # while full_arch_testing == 1 takes 9m20s.
    364 set full_arch_testing 0
    365 
    366 set tested_archs {}
    367 foreach_with_prefix arch $supported_archs {
    368     if {$arch == "auto"} {
    369 	# Avoid duplicate testing.
    370 	continue
    371     }
    372     test_parse_numbers $arch
    373 }
    374