1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
|
# Copyright 2014-2024 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Utility procedures, shared between test suite domains.
# A helper procedure to retrieve commands to send to GDB before a program
# is started.
proc gdb_init_commands {} {
set commands ""
if [target_info exists gdb_init_command] {
lappend commands [target_info gdb_init_command]
}
if [target_info exists gdb_init_commands] {
set commands [concat $commands [target_info gdb_init_commands]]
}
return $commands
}
# Given an input string, adds backslashes as needed to create a
# regexp that will match the string.
proc string_to_regexp {str} {
set result $str
regsub -all {[]?*+.|(){}^$\[\\]} $str {\\&} result
return $result
}
# Convenience function that calls string_to_regexp for each arg, and
# joins the results using "\r\n".
proc multi_line_string_to_regexp { args } {
set res [lmap arg $args {string_to_regexp $arg}]
return [multi_line {*}$res]
}
# Given a list of strings, adds backslashes as needed to each string to
# create a regexp that will match the string, and join the result.
proc string_list_to_regexp { args } {
set result ""
foreach arg $args {
set arg [string_to_regexp $arg]
append result $arg
}
return $result
}
# Wrap STR in an ANSI terminal escape sequences -- one to set the
# style to STYLE, and one to reset the style to the default. The
# return value is suitable for use as a regular expression.
# STYLE can either be the payload part of an ANSI terminal sequence,
# or a shorthand for one of the gdb standard styles: "file",
# "function", "variable", "address", etc.
proc style {str style} {
switch -exact -- $style {
title { set style 1 }
command { set style 1 }
file { set style 32 }
function { set style 33 }
highlight { set style 31 }
variable { set style 36 }
address { set style 34 }
metadata { set style 2 }
version { set style "35;1" }
line-number { set style 2 }
none { return $str }
}
return "\033\\\[${style}m${str}\033\\\[m"
}
# gdb_get_bp_addr num
#
# Purpose:
# Get address of a particular breakpoint.
#
# Parameter:
# The parameter "num" indicates the number of the breakpoint to get.
# Note that *currently* this parameter must be an integer value.
# E.g., -1 means that we're gonna get the first internal breakpoint;
# 2 means to get the second user-defined breakpoint.
#
# Return:
# First address for a particular breakpoint.
#
# TODO:
# It would be nice if this procedure could accept floating point value.
# E.g., 'gdb_get_bp_addr 1.2' means to get the address of the second
# location of breakpoint #1.
#
proc gdb_get_bp_addr { num } {
gdb_test_multiple "maint info break $num" "find address of specified bp $num" {
-re -wrap ".*(0x\[0-9a-f\]+).*" {
return $expect_out(1,string)
}
}
return ""
}
# Compare the version numbers in L1 to those in L2 using OP, and
# return 1 if the comparison is true. OP can be "<", "<=", ">", ">=",
# or "==". It is ok if the lengths of the lists differ.
proc version_compare { l1 op l2 } {
switch -exact $op {
"==" -
"<=" -
"<" {}
">=" {
# a >= b => b <= a
set x $l2
set l2 $l1
set l1 $x
set op "<="
}
">" {
# a > b => b < a
set x $l2
set l2 $l1
set l1 $x
set op "<"
}
default { error "unsupported op: $op" }
}
# Handle ops < and ==.
foreach v1 $l1 v2 $l2 {
if {$v1 == ""} {
# This is: "1.2 OP 1.2.1".
if {$op != "=="} {
return 1
}
return 0
}
if {$v2 == ""} {
# This is: "1.2.1 OP 1.2".
return 0
}
if {$v1 == $v2} {
continue
}
return [expr $v1 $op $v2]
}
if {$op == "<"} {
# They are equal.
return 0
}
return 1
}
# Acquire lock file LOCKFILE. Tries forever until the lock file is
# successfully created.
proc lock_file_acquire {lockfile} {
verbose -log "acquiring lock file: $::subdir/${::gdb_test_file_name}.exp"
while {true} {
if {![catch {open $lockfile {WRONLY CREAT EXCL}} rc]} {
set msg "locked by $::subdir/${::gdb_test_file_name}.exp"
verbose -log "lock file: $msg"
# For debugging, put info in the lockfile about who owns
# it.
puts $rc $msg
flush $rc
return [list $rc $lockfile]
}
after 10
}
}
# Release a lock file.
proc lock_file_release {info} {
verbose -log "releasing lock file: $::subdir/${::gdb_test_file_name}.exp"
if {![catch {fconfigure [lindex $info 0]}]} {
if {![catch {
close [lindex $info 0]
file delete -force [lindex $info 1]
} rc]} {
return ""
} else {
return -code error "Error releasing lockfile: '$rc'"
}
} else {
error "invalid lock"
}
}
# Return directory where we keep lock files.
proc lock_dir {} {
if { [info exists ::GDB_LOCK_DIR] } {
# When using check//.
return $::GDB_LOCK_DIR
}
return [make_gdb_parallel_path cache]
}
# Run body under lock LOCK_FILE.
proc with_lock { lock_file body } {
if {[info exists ::GDB_PARALLEL]} {
set lock_file [file join [lock_dir] $lock_file]
set lock_rc [lock_file_acquire $lock_file]
}
set code [catch {uplevel 1 $body} result]
if {[info exists ::GDB_PARALLEL]} {
lock_file_release $lock_rc
}
if {$code == 1} {
global errorInfo errorCode
return -code $code -errorinfo $errorInfo -errorcode $errorCode $result
} else {
return -code $code $result
}
}
|