From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20105 invoked by alias); 7 Feb 2008 19:28:56 -0000 Received: (qmail 20075 invoked by uid 9697); 7 Feb 2008 19:28:56 -0000 Date: Thu, 07 Feb 2008 19:28:00 -0000 Message-ID: <20080207192856.20060.qmail@sourceware.org> From: pmachata@sourceware.org To: frysk-cvs@sourceware.org Subject: [SCM] master: Fix TestFtrace to use -sys commandline option X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 0fb13e7cc5f975675b50a0e349db34cbcdb0470d X-Git-Newrev: eac0c5123c615be6efa3ca1738175ea0a59be132 Mailing-List: contact frysk-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: frysk-cvs-owner@sourceware.org Reply-To: frysk@sourceware.org X-SW-Source: 2008-q1/txt/msg00172.txt.bz2 The branch, master has been updated via eac0c5123c615be6efa3ca1738175ea0a59be132 (commit) via 21a3a0c9c925dedd11d3d808c9e542930fb44197 (commit) via 9ca35ed4d1a06162a77b0030143cb4591e3ac69c (commit) from 0fb13e7cc5f975675b50a0e349db34cbcdb0470d (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit eac0c5123c615be6efa3ca1738175ea0a59be132 Author: Petr Machata Date: Thu Feb 7 20:25:50 2008 +0100 Fix TestFtrace to use -sys commandline option commit 21a3a0c9c925dedd11d3d808c9e542930fb44197 Author: Petr Machata Date: Thu Feb 7 17:52:37 2008 +0100 Support fine-grained selection of syscalls to trace * Option -sys, behaves much like -plt/-sym/-dyn (no @/@@ support) * The code calls for some refactoring, there's a lot of duplication. commit 9ca35ed4d1a06162a77b0030143cb4591e3ac69c Author: Petr Machata Date: Thu Feb 7 17:34:22 2008 +0100 Making SyscallTable more public about its syscalls * getNumSyscalls: public function answers number of entries in system call table. * getSyscall(long): has become public ----------------------------------------------------------------------- Summary of changes: frysk-core/frysk/bindir/ChangeLog | 15 +- frysk-core/frysk/bindir/TestFtrace.java | 4 + frysk-core/frysk/bindir/ftrace.java | 266 +++++++++++++++----- frysk-core/frysk/ftrace/ChangeLog | 11 + frysk-core/frysk/ftrace/Ftrace.java | 109 +++++---- frysk-core/frysk/isa/syscalls/ChangeLog | 9 + .../frysk/isa/syscalls/LinuxIA32SyscallTable.java | 6 +- .../frysk/isa/syscalls/LinuxPPC32SyscallTable.java | 6 +- .../frysk/isa/syscalls/LinuxPPC64SyscallTable.java | 6 +- .../frysk/isa/syscalls/LinuxX8664SyscallTable.java | 6 +- frysk-core/frysk/isa/syscalls/SyscallTable.java | 7 +- 11 files changed, 332 insertions(+), 113 deletions(-) First 500 lines of diff: diff --git a/frysk-core/frysk/bindir/ChangeLog b/frysk-core/frysk/bindir/ChangeLog index 5525a65..ee65d19 100644 --- a/frysk-core/frysk/bindir/ChangeLog +++ b/frysk-core/frysk/bindir/ChangeLog @@ -2,10 +2,21 @@ * fmaps.java: Refactor to use ProcStopUtil. +2008-02-07 Petr Machata + + * ftrace.java: Support fine-grained selection of syscalls to + trace/stack trace on. Remove -t, -s options. + (Rule): New abstract class. + (SyscallRule, ByNumberSyscallRule, ByRegexpSyscallRule): New classes. + (MyFtraceController.sysRules): New variable. + (.gotSysRules): New method. + (.computeSyscallWorkingSet): New method. + (.parseSyscallRules): New method. + 2008-02-07 Andrew Cagney - + * fstep.java: Update to use Host.requestProc(int,FindProc). - + 2008-02-06 Teresa Thomas * fdebuginfo.java: Refactor, use ProcStopUtil. diff --git a/frysk-core/frysk/bindir/TestFtrace.java b/frysk-core/frysk/bindir/TestFtrace.java index d887ed7..1692d7c 100644 --- a/frysk-core/frysk/bindir/TestFtrace.java +++ b/frysk-core/frysk/bindir/TestFtrace.java @@ -62,6 +62,7 @@ public class TestFtrace extends TestLib { return; TearDownExpect e = new TearDownExpect(new String[] { Config.getBinFile("ftrace").getAbsolutePath(), + "-sys=", "/bin/ls" }); e.expect("execve"); @@ -74,6 +75,7 @@ public class TestFtrace extends TestLib { Task task = child.findTaskUsingRefresh(true); TearDownExpect e = new TearDownExpect(new String[] { Config.getBinFile("ftrace").getAbsolutePath(), + "-sys=", ""+task.getProc().getPid() }); e.expect(""+task.getProc().getPid()+"."+ task.getTid()); @@ -88,6 +90,7 @@ public class TestFtrace extends TestLib { Task task = child.findTaskUsingRefresh(true); TearDownExpect e = new TearDownExpect(new String[] { Config.getBinFile("ftrace").getAbsolutePath(), + "-sys=", "-c", ""+task.getProc().getPid() }); @@ -100,6 +103,7 @@ public class TestFtrace extends TestLib { public void testFtraceHandlesPrcoessNotFound() { TearDownExpect e = new TearDownExpect(new String[] { Config.getBinFile("ftrace").getAbsolutePath(), + "-sys=", "0" }); e.expect("No process with ID 0 found"); diff --git a/frysk-core/frysk/bindir/ftrace.java b/frysk-core/frysk/bindir/ftrace.java index 9dde5c7..2a6501b 100644 --- a/frysk-core/frysk/bindir/ftrace.java +++ b/frysk-core/frysk/bindir/ftrace.java @@ -42,17 +42,21 @@ package frysk.bindir; import inua.util.PrintWriter; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.StringTokenizer; import java.util.logging.*; import java.util.regex.*; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import frysk.isa.syscalls.SyscallTable; +import frysk.isa.syscalls.Syscall; + import frysk.proc.ProcId; import frysk.proc.Task; @@ -69,41 +73,103 @@ import lib.dwfl.ElfSymbolVersion; import gnu.classpath.tools.getopt.Option; import gnu.classpath.tools.getopt.OptionException; -class WorkingSetRule +abstract class Rule { final public boolean addition; final public boolean stackTrace; - /** - * Object that performs a pattern matching of symbol - * name. null for "anything" matcher. - */ - final public Pattern namePattern; + protected Rule(boolean addition, boolean stackTrace) { + this.addition = addition; + this.stackTrace = stackTrace; + } + + public String toString() { + return "" + + (this.addition ? "" : "-") + + (this.stackTrace ? "#" : ""); + } + + abstract public boolean matches(Object traceable); +} +class WorkingSetRule + extends Rule +{ /** See namePattern */ final public Pattern sonamePattern, versionPattern; - public WorkingSetRule(boolean addition, boolean stackTrace, String nameRe, String sonameRe, String versionRe) { - this.addition = addition; - this.stackTrace = stackTrace; - this.namePattern = Pattern.compile((nameRe != null) ? nameRe : ".*"); + /** + * Object that performs a pattern matching of a symbol name. null + * for "anything" matcher. + */ + final public Pattern namePattern; + + public WorkingSetRule(boolean addition, boolean stackTrace, + String nameRe, String sonameRe, String versionRe) { + super (addition, stackTrace); this.sonamePattern = Pattern.compile((sonameRe != null) ? sonameRe : ".*"); this.versionPattern = Pattern.compile((versionRe != null) ? versionRe : ".*"); + this.namePattern = Pattern.compile((nameRe != null) ? nameRe : ".*"); } public String toString() { - return "" - + (this.addition ? "" : "-") - + (this.stackTrace ? "#" : "") + return super.toString() + this.namePattern.pattern() + "@" + this.sonamePattern.pattern() + "@@" + this.versionPattern.pattern(); } + + public boolean matches(Object traceable) { + throw new AssertionError("NYI"); + } +} + +class SyscallRule + extends Rule +{ + public SyscallRule(boolean addition, boolean stackTrace) { + super (addition, stackTrace); + } + + public boolean matches(Object traceable) { + return true; + } +} + +class ByNumberSyscallRule + extends SyscallRule +{ + long number; + public ByNumberSyscallRule(boolean addition, boolean stackTrace, long number) { + super (addition, stackTrace); + this.number = number; + } + + public boolean matches(Object traceable) { + Syscall syscall = (Syscall)traceable; + return syscall.getNumber() == number; + } +} + +class ByRegexpSyscallRule + extends SyscallRule +{ + Pattern pattern; + public ByRegexpSyscallRule(boolean addition, boolean stackTrace, String regexp) { + super (addition, stackTrace); + this.pattern = Pattern.compile(regexp); + } + + public boolean matches(Object traceable) { + Syscall syscall = (Syscall)traceable; + return this.pattern.matcher(syscall.getName()).matches(); + } } class MyFtraceController implements Ftrace.Controller, - Ftrace.StackTracedSymbolsProvider + Ftrace.StackTracedSymbolsProvider, + Ftrace.TracedSyscallProvider { protected static final Logger logger = Logger.getLogger("frysk"); @@ -111,11 +177,12 @@ class MyFtraceController private final List pltRules = new ArrayList(); private final List dynRules = new ArrayList(); private final List symRules = new ArrayList(); + private final List sysRules = new ArrayList(); // Which symbols should yield a stack trace. private HashSet symbolsStackTraceSet = new HashSet(); - public boolean shouldStackTraceOn(Symbol symbol) { + public boolean shouldStackTraceOnSymbol(Symbol symbol) { return symbolsStackTraceSet.contains(symbol); } @@ -136,6 +203,11 @@ class MyFtraceController this.symRules.addAll(rules); } + public void gotSysRules(List rules) { + logger.log(Level.FINER, "Got " + rules.size() + " syscall rules."); + this.sysRules.addAll(rules); + } + private boolean checkVersionMatches(final TracePoint tp, final WorkingSetRule rule) { ElfSymbolVersion[] vers = (tp.origin == TracePointOrigin.PLT) @@ -178,6 +250,59 @@ class MyFtraceController return false; } + public Map computeSyscallWorkingSet(Task task) { + HashSet workingSet = new HashSet(); + HashSet stackTraceSet = new HashSet(); + SyscallTable syscallTable = task.getSyscallTable(); + long n = syscallTable.getNumSyscalls(); + ArrayList candidates = new ArrayList(); + for (long i = 0; i < n; ++i) + candidates.add(syscallTable.getSyscall(i)); + + for (Iterator it = sysRules.iterator(); it.hasNext(); ) { + final Rule rule = (Rule)it.next(); + logger.log(Level.FINEST, "Considering syscall rule " + rule + "."); + + if (rule.addition) + // For '+' rules iterate over candidates, + // and add what matches to workingSet, and + // maybe to stackTraceSet. + for (Iterator jt = candidates.iterator(); jt.hasNext(); ) { + Object candidate = jt.next(); + if (rule.matches(candidate)) { + if (workingSet.add(candidate)) + logger.log(Level.CONFIG, rule + ": add `" + candidate + "'."); + if (rule.stackTrace + && stackTraceSet.add(candidate)) + logger.log(Level.CONFIG, rule + ": stack trace on `" + candidate + "'."); + } + } + else { + // For '-' or '-#' rules iterate over + // workingSet or stackTraceSet, and remove + // what matches. + Set iterateOver = rule.stackTrace ? stackTraceSet : workingSet; + for (Iterator jt = iterateOver.iterator(); jt.hasNext(); ) { + Object candidate = jt.next(); + if (rule.matches(candidate)) { + jt.remove(); + if (!rule.stackTrace) + stackTraceSet.remove(candidate); + logger.log(Level.CONFIG, rule + ": remove `" + candidate + "'."); + } + } + } + } + + // Apply the two sets. + Map ret = new HashMap(); + for (Iterator it = workingSet.iterator(); it.hasNext(); ) { + Object syscall = it.next(); + ret.put(syscall, Boolean.valueOf(stackTraceSet.contains(syscall))); + } + return ret; + } + private boolean isInterpOf(ObjectFile objf, String exe) { java.io.File exefn = new java.io.File(exe); @@ -204,6 +329,8 @@ class MyFtraceController // Set, incrementally built set of tracepoints // that should stacktrace. final Set stackTraceSet = new HashSet(); + + // Do a lazy init. With symbol tables this can be very beneficial, because certain symbol boolean candidatesInited = false; // Loop through all the rules, and use them to build @@ -211,7 +338,7 @@ class MyFtraceController // lazily inside the loop. for (Iterator it = rules.iterator(); it.hasNext(); ) { final WorkingSetRule rule = (WorkingSetRule)it.next(); - logger.log(Level.FINEST, "Considering rule " + rule + "."); + logger.log(Level.FINEST, "Considering symbol rule " + rule + "."); // MAIN is meta-soname meaning "main executable". if ((rule.sonamePattern.pattern().equals("MAIN") @@ -305,12 +432,13 @@ class ftrace final List pltRules = new ArrayList(); final List dynRules = new ArrayList(); final List symRules = new ArrayList(); + final List sysRules = new ArrayList(); final MyFtraceController controller = new MyFtraceController(); boolean allowInterpTracing = false; Ftrace tracer = new Ftrace(); - private List parseRules(String arg) { + private List parseSymbolRules(String arg) { String[] strs = arg.split(",", -1); List rules = new ArrayList(); for (int i = 0; i < strs.length; ++i) { @@ -368,6 +496,53 @@ class ftrace return rules; } + private List parseSyscallRules(String arg) { + String[] strs = arg.split(",", -1); + Pattern sysnumPat = Pattern.compile("[0-9]+"); + List rules = new ArrayList(); + for (int i = 0; i < strs.length; ++i) { + // 14, SYS14: syscall number 14 + // otherwise: syscall whose name matches regular expression + String str = strs[i]; + final SyscallRule rule; + final boolean addition; + final boolean stackTrace; + + if (str.length() > 0 && str.charAt(0) == '-') { + addition = false; + str = str.substring(1); + } + else + addition = true; + + if (str.length() > 0 && str.charAt(0) == '#') { + stackTrace = true; + str = str.substring(1); + } + else + stackTrace = false; + + if (sysnumPat.matcher(str).matches()) { + logger.log(Level.FINE, i + ": " + str + ": by number rule"); + if (str.startsWith("SYS")) + str = str.substring(3); + long sysnum = (new Long(str)).longValue(); + rule = new ByNumberSyscallRule(addition, stackTrace, sysnum); + } + else if (!str.equals("")) { + logger.log(Level.FINE, i + ": " + str + ": by regexp rule"); + rule = new ByRegexpSyscallRule(addition, stackTrace, str); + } + else { + logger.log(Level.FINE, i + ": " + str + ": \"everything\" rule"); + rule = new SyscallRule(addition, stackTrace); + } + + rules.add(rule); + } + return rules; + } + private void addOptions(CommandlineParser parser) { parser.add(new Option('o', "output file name", "FILE") { @@ -391,22 +566,6 @@ class ftrace } }); - parser.add(new Option("trace", 't', "syscalls to trace", "CALL[,CALL]...") { - public void parsed(String arg) throws OptionException - { - StringTokenizer st = new StringTokenizer(arg, ","); - while (st.hasMoreTokens()) - { - String name = st.nextToken(); - // FIXME: there's no good way to error out if the - // syscall is unknown. - if (tracedCalls == null) - tracedCalls = new HashSet(); - tracedCalls.add(name); - } - } - }); - parser.add(new Option('p', "pid to trace", "PID") { public void parsed(String arg) throws OptionException { @@ -422,29 +581,6 @@ class ftrace } }); - parser.add(new Option('s', "stack trace system calls", "CALL[,CALL]...") { - public void parsed(String arg) throws OptionException - { - StringTokenizer st = new StringTokenizer(arg, ","); - HashSet set = new HashSet(2); - while (st.hasMoreTokens()) - { - String name = st.nextToken(); - // FIXME: there's no good way to error out if the - // syscall is unknown. - set.add(name); - } - tracer.setSyscallStackTracing(set); - } - }); - - parser.add(new Option('S', "don't trace system calls") { - public void parsed(String arg) throws OptionException - { - tracer.setDontTraceSyscalls(); - } - }); - parser.add(new Option('m', "print out when library is mapped or unmapped") { public void parsed(String arg) throws OptionException { @@ -459,6 +595,13 @@ class ftrace } }); + parser.add(new Option("sys", "trace system calls", "CALL[,CALL]...") { + public void parsed(String arg) throws OptionException + { + sysRules.add(arg); + } + }); + parser.add(new Option("plt", "trace library calls done via PLT", "RULE[,RULE]...") { public void parsed(String arg) { pltRules.add(arg); @@ -524,14 +667,17 @@ class ftrace // We need to load and apply rules separately, to get all log // messages. for (Iterator it = pltRules.iterator(); it.hasNext(); ) - controller.gotPltRules(parseRules((String)it.next())); + controller.gotPltRules(parseSymbolRules((String)it.next())); for (Iterator it = dynRules.iterator(); it.hasNext(); ) - controller.gotDynRules(parseRules((String)it.next())); + controller.gotDynRules(parseSymbolRules((String)it.next())); for (Iterator it = symRules.iterator(); it.hasNext(); ) - controller.gotSymRules(parseRules((String)it.next())); + controller.gotSymRules(parseSymbolRules((String)it.next())); + for (Iterator it = sysRules.iterator(); it.hasNext(); ) + controller.gotSysRules(parseSyscallRules((String)it.next())); tracer.setWriter(writer); tracer.setTraceFunctions(controller, controller); + tracer.setTraceSyscalls(controller); if (commandAndArguments != null) { String[] cmd = (String[]) commandAndArguments.toArray(new String[0]); diff --git a/frysk-core/frysk/ftrace/ChangeLog b/frysk-core/frysk/ftrace/ChangeLog index 904015c..ed886b1 100644 --- a/frysk-core/frysk/ftrace/ChangeLog +++ b/frysk-core/frysk/ftrace/ChangeLog @@ -2,6 +2,17 @@ * Ftrace.java: Update to use Host.requestProc(int,FindProc). +2008-02-07 Petr Machata + + * Ftrace.java: Support fine-grained selection of syscalls to + trace/stack trace on. + (TracedSyscallProvider): New interface. + (shouldStackTraceOn): Reanamed to shouldStackTraceOnSymbol. + (tracedSyscallProvider): New member variable. + (setDontTraceSyscalls): Renamed to setTraceSyscalls. + (setSyscallStackTracing): Deleted. + (syscallSetForTask): New member variable. + 2008-01-24 Andrew Cagney * MappingGuard.java: Update to match diff --git a/frysk-core/frysk/ftrace/Ftrace.java b/frysk-core/frysk/ftrace/Ftrace.java index d49eef1..ca8ce0f 100644 --- a/frysk-core/frysk/ftrace/Ftrace.java +++ b/frysk-core/frysk/ftrace/Ftrace.java @@ -72,13 +72,11 @@ public class Ftrace boolean traceChildren = false; // True if we're tracing syscalls. hooks/post-receive -- frysk system monitor/debugger