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