ltrace.exp revision 0c4f66d02980f16989ab9a70e01066df78cb48f8
1# This file is part of ltrace. 2# Copyright (C) 2006 Yao Qi, IBM Corporation 3# 4# This program is free software; you can redistribute it and/or 5# modify it under the terms of the GNU General Public License as 6# published by the Free Software Foundation; either version 2 of the 7# License, or (at your option) any later version. 8# 9# This program is distributed in the hope that it will be useful, but 10# WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12# General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program; if not, write to the Free Software 16# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 17# 02110-1301 USA 18 19# Generic ltrace test subroutines that should work for any target. If these 20# need to be modified for any target, it can be done with a variable 21# or by passing arguments. 22 23source $objdir/env.exp 24 25if [info exists TOOL_EXECUTABLE] { 26 set LTRACE $TOOL_EXECUTABLE 27} else { 28 set LTRACE $objdir/../ltrace 29} 30 31if {[info exists VALGRIND] && ![string equal $VALGRIND {}]} { 32 verbose "Running under valgrind command: `$VALGRIND'" 33 set LTRACE "$VALGRIND $LTRACE" 34} 35 36set LTRACE_OPTIONS ""; 37set LTRACE_ARGS ""; 38 39# ltrace_compile SOURCE DEST TYPE OPTIONS 40# 41# Compile PUT(program under test) by native compiler. ltrace_compile runs 42# the right compiler, and TCL captures the output, and I evaluate the output. 43# 44# SOURCE is the name of program under test, with full directory. 45# DEST is the name of output of compilation, with full directory. 46# TYPE is an enum-like variable to affect the format or result of compiler 47# output. Values: 48# executable if output is an executable. 49# object if output is an object. 50# OPTIONS is option to compiler in this compilation. 51proc ltrace_compile {source dest type options} { 52 global LTRACE_TESTCASE_OPTIONS; 53 54 if {![string equal "object" $type]} { 55 # Add platform-specific options if a shared library was specified using 56 # "shlib=librarypath" in OPTIONS. 57 set new_options "" 58 set shlib_found 0 59 60 foreach opt $options { 61 if [regexp {^shlib=(.*)} $opt dummy_var shlib_name] { 62 if [test_compiler_info "xlc*"] { 63 # IBM xlc compiler doesn't accept shared library named other 64 # than .so: use "-Wl," to bypass this 65 lappend source "-Wl,$shlib_name" 66 } else { 67 lappend source $shlib_name 68 } 69 70 if {$shlib_found == 0} { 71 set shlib_found 1 72 73 if { ([test_compiler_info "gcc-*"]&& ([istarget "powerpc*-*-aix*"]|| [istarget "rs6000*-*-aix*"] ))} { 74 lappend options "additional_flags=-L${objdir}/${subdir}" 75 } elseif { [istarget "mips-sgi-irix*"] } { 76 lappend options "additional_flags=-rpath ${objdir}/${subdir}" 77 } 78 } 79 80 } else { 81 lappend new_options $opt 82 } 83 } 84 85 #end of for loop 86 set options $new_options 87 } 88 89 # dump some information for debug purpose. 90 verbose "options are $options" 91 verbose "source is $source $dest $type $options" 92 93 # Wipe the DEST file, so that we don't end up running an obsolete 94 # version of the binary. 95 exec rm -f $dest 96 97 set result [target_compile $source $dest $type $options]; 98 verbose "result is $result" 99 regsub "\[\r\n\]*$" "$result" "" result; 100 regsub "^\[\r\n\]*" "$result" "" result; 101 if { $result != "" && [lsearch $options quiet] == -1} { 102 clone_output "compile failed for ltrace test, $result" 103 } 104 return $result; 105} 106 107proc get_compiler_info {binfile args} { 108 # For compiler.c and compiler.cc 109 global srcdir 110 111 # I am going to play with the log to keep noise out. 112 global outdir 113 global tool 114 115 # These come from compiler.c or compiler.cc 116 global compiler_info 117 118 # Legacy global data symbols. 119 #global gcc_compiled 120 121 # Choose which file to preprocess. 122 set ifile "${srcdir}/lib/compiler.c" 123 if { [llength $args] > 0 && [lindex $args 0] == "c++" } { 124 set ifile "${srcdir}/lib/compiler.cc" 125 } 126 127 # Run $ifile through the right preprocessor. 128 # Toggle ltrace.log to keep the compiler output out of the log. 129 #log_file 130 set cppout [ ltrace_compile "${ifile}" "" preprocess [list "$args" quiet] ] 131 #log_file -a "$outdir/$tool.log" 132 133 # Eval the output. 134 set unknown 0 135 foreach cppline [ split "$cppout" "\n" ] { 136 if { [ regexp "^#" "$cppline" ] } { 137 # line marker 138 } elseif { [ regexp "^\[\n\r\t \]*$" "$cppline" ] } { 139 # blank line 140 } elseif { [ regexp "^\[\n\r\t \]*set\[\n\r\t \]" "$cppline" ] } { 141 # eval this line 142 verbose "get_compiler_info: $cppline" 2 143 eval "$cppline" 144 } else { 145 # unknown line 146 verbose "get_compiler_info: $cppline" 147 set unknown 1 148 } 149 } 150 151 # Reset to unknown compiler if any diagnostics happened. 152 if { $unknown } { 153 set compiler_info "unknown" 154 } 155 return 0 156} 157 158proc test_compiler_info { {compiler ""} } { 159 global compiler_info 160 161 if [string match "" $compiler] { 162 if [info exists compiler_info] { 163 verbose "compiler_info=$compiler_info" 164 # if no arg, return the compiler_info string 165 return $compiler_info 166 } else { 167 perror "No compiler info found." 168 } 169 } 170 171 return [string match $compiler $compiler_info] 172} 173 174proc ltrace_compile_shlib {sources dest options} { 175 set obj_options $options 176 verbose "+++++++ [test_compiler_info]" 177 switch -glob [test_compiler_info] { 178 "xlc-*" { 179 lappend obj_options "additional_flags=-qpic" 180 } 181 "gcc-*" { 182 if { !([istarget "powerpc*-*-aix*"] 183 || [istarget "rs6000*-*-aix*"]) } { 184 lappend obj_options "additional_flags=-fpic" 185 } 186 } 187 "xlc++-*" { 188 lappend obj_options "additional_flags=-qpic" 189 } 190 191 default { 192 fail "Bad compiler!" 193 } 194 } 195 196 if {![LtraceCompileObjects $sources $obj_options objects]} { 197 return -1 198 } 199 200 set link_options $options 201 if { [test_compiler_info "xlc-*"] || [test_compiler_info "xlc++-*"]} { 202 lappend link_options "additional_flags=-qmkshrobj" 203 } else { 204 lappend link_options "additional_flags=-shared" 205 } 206 if {[ltrace_compile "${objects}" "${dest}" executable $link_options] != ""} { 207 return -1 208 } 209} 210 211# LtraceCompileObjects -- 212# 213# Compile each source file into an object file. ltrace_compile 214# is called to perform actual compilation. 215# 216# Arguments: 217# sources List of source files. 218# 219# options Options for ltrace_compile. 220# 221# retName Variable where the resulting list of object names is 222# to be placed. 223# Results: 224# Returns true or false depending on whether there were any 225# errors. If it returns true, then variable referenced by 226# retName contains list of object files, produced by compiling 227# files in sources list. 228 229proc LtraceCompileObjects {sources options retName} { 230 upvar $retName ret 231 set ret {} 232 233 foreach source $sources { 234 set sourcebase [file tail $source] 235 set dest $source.o 236 verbose "LtraceCompileObjects: $source -> $dest" 237 if {[ltrace_compile $source $dest object $options] != ""} { 238 return false 239 } 240 lappend ret $dest 241 } 242 243 return true 244} 245 246# 247# ltrace_options OPTIONS_LIST 248# Pass ltrace commandline options. 249# 250proc ltrace_options { args } { 251 252 global LTRACE_OPTIONS 253 set LTRACE_OPTIONS $args 254} 255 256# 257# ltrace_args ARGS_LIST 258# Pass ltrace'd program its own commandline options. 259# 260proc ltrace_args { args } { 261 262 global LTRACE_ARGS 263 set LTRACE_ARGS $args 264} 265 266# 267# handle run-time library paths 268# 269proc ld_library_path { args } { 270 271 set ALL_LIBRARY_PATHS { } 272 if [info exists LD_LIBRARY_PATH] { 273 lappend ALL_LIBRARY_PATHS $LD_LIBRARY_PATH 274 } 275 global libelf_LD_LIBRARY_PATH 276 if {[string length $libelf_LD_LIBRARY_PATH] > 0} { 277 lappend ALL_LIBRARY_PATHS $libelf_LD_LIBRARY_PATH 278 } 279 global libunwind_LD_LIBRARY_PATH 280 if {[string length $libunwind_LD_LIBRARY_PATH] > 0} { 281 lappend ALL_LIBRARY_PATHS $libunwind_LD_LIBRARY_PATH 282 } 283 lappend ALL_LIBRARY_PATHS $args 284 join $ALL_LIBRARY_PATHS ":" 285} 286 287# 288# ltrace_runtest LD_LIBRARY_PATH BIN FILE 289# Trace the execution of BIN and return result. 290# 291# BIN is program-under-test. 292# LD_LIBRARY_PATH is the env for program-under-test to run. 293# FILE is to save the output from ltrace with default name $BIN.ltrace. 294# Retrun output from ltrace. 295# 296proc ltrace_runtest { args } { 297 298 global LTRACE 299 global LTRACE_OPTIONS 300 global LTRACE_ARGS 301 302 verbose "LTRACE = $LTRACE" 303 304 set LD_LIBRARY_PATH_ [ld_library_path [lindex $args 0]] 305 set BIN [lindex $args 1] 306 307 # specify the output file, the default one is $BIN.ltrace 308 if [llength $args]==3 then { 309 set file [lindex $args 2] 310 } else { 311 set file $BIN.ltrace 312 } 313 314 # Remove the file first. If ltrace fails to overwrite it, we 315 # would be comparing output to an obsolete run. 316 exec rm -f $file 317 318 # append this option to LTRACE_OPTIONS. 319 lappend LTRACE_OPTIONS "-o" 320 lappend LTRACE_OPTIONS "$file" 321 verbose "LTRACE_OPTIONS = $LTRACE_OPTIONS" 322 #ltrace the PUT. 323 catch "exec sh -c {export LD_LIBRARY_PATH=$LD_LIBRARY_PATH_; $LTRACE $LTRACE_OPTIONS $BIN $LTRACE_ARGS;exit}" output 324 325 # return output from ltrace. 326 return $output 327} 328 329# 330# ltrace_saveoutput OUTPUT FILE 331# Save OUTPUT from ltrace to file FILE. 332# OUTPUT is output from ltrace or return value of ltrace_runtest. 333# FILE is file save output. 334# 335proc ltrace_saveoutput { args } { 336 337 set output [lindex $args 0] 338 set file [lindex $args 1] 339 340 set fd [open $file w] 341 puts $fd $output 342 close $fd 343} 344 345 346# 347# ltrace_verify_output FILE_TO_SEARCH PATTERN MAX_LINE 348# Verify the ltrace output by comparing the number of PATTERN in 349# FILE_TO_SEARCH with INSTANCE_NO. Do not specify INSTANCE_NO if 350# instance number is ignored in this test. 351# Reutrn: 352# 0 = number of PATTERN in FILE_TO_SEARCH inqual to INSTANCE_NO. 353# 1 = number of PATTERN in FILE_TO_SEARCH qual to INSTANCE_NO. 354# 355proc ltrace_verify_output { file_to_search pattern {instance_no 0} {grep_command "grep"}} { 356 357 # compute the number of PATTERN in FILE_TO_SEARCH by grep and wc. 358 catch "exec sh -c {$grep_command \"$pattern\" $file_to_search | wc -l ;exit}" output 359 verbose "output = $output" 360 361 if [ regexp "syntax error" $output ] then { 362 fail "Invalid regular expression $pattern" 363 } elseif { $instance_no == 0 } then { 364 if { $output == 0 } then { 365 fail "Fail to find $pattern in $file_to_search" 366 } else { 367 pass "$pattern in $file_to_search" 368 } 369 } elseif { $output >= $instance_no } then { 370 pass "$pattern in $file_to_search for $output times" 371 } else { 372 fail "$pattern in $file_to_search for $output times, should be $instance_no" 373 } 374} 375