001 // This file is part of the program FRYSK. 002 // 003 // Copyright 2005, 2006, 2007, 2008, Red Hat Inc. 004 // 005 // FRYSK is free software; you can redistribute it and/or modify it 006 // under the terms of the GNU General Public License as published by 007 // the Free Software Foundation; version 2 of the License. 008 // 009 // FRYSK is distributed in the hope that it will be useful, but 010 // WITHOUT ANY WARRANTY; without even the implied warranty of 011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 // General Public License for more details. 013 // 014 // You should have received a copy of the GNU General Public License 015 // along with FRYSK; if not, write to the Free Software Foundation, 016 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 017 // 018 // In addition, as a special exception, Red Hat, Inc. gives You the 019 // additional right to link the code of FRYSK with code not covered 020 // under the GNU General Public License ("Non-GPL Code") and to 021 // distribute linked combinations including the two, subject to the 022 // limitations in this paragraph. Non-GPL Code permitted under this 023 // exception must only link to the code of FRYSK through those well 024 // defined interfaces identified in the file named EXCEPTION found in 025 // the source code files (the "Approved Interfaces"). The files of 026 // Non-GPL Code may instantiate templates or use macros or inline 027 // functions from the Approved Interfaces without causing the 028 // resulting work to be covered by the GNU General Public 029 // License. Only Red Hat, Inc. may make changes or additions to the 030 // list of Approved Interfaces. You must obey the GNU General Public 031 // License in all respects for all of the FRYSK code and other code 032 // used in conjunction with FRYSK except the Non-GPL Code covered by 033 // this exception. If you modify this file, you may extend this 034 // exception to your version of the file, but you are not obligated to 035 // do so. If you do not wish to provide this exception without 036 // modification, you must delete this exception statement from your 037 // version and license this file solely under the GPL without 038 // exception. 039 040 package frysk.ftrace; 041 042 import java.util.ArrayList; 043 import java.util.HashMap; 044 import java.util.HashSet; 045 import java.util.Iterator; 046 import java.util.List; 047 import java.util.Map; 048 import java.util.Set; 049 050 import lib.dwfl.DwflModule; 051 import lib.dwfl.ModuleElfBias; 052 053 import frysk.dwfl.ObjectFile; 054 import frysk.isa.signals.SignalTable; 055 import frysk.isa.syscalls.SyscallTable; 056 import frysk.proc.Task; 057 import frysk.rsl.Log; 058 import frysk.rsl.LogFactory; 059 import frysk.symtab.DwflSymbol; 060 import frysk.symtab.PLTEntry; 061 import frysk.symtab.SymbolFactory; 062 063 public class FtraceController 064 implements Ftrace.Controller, 065 Ftrace.StackTracedSymbolsProvider, 066 Ftrace.TracedSyscallProvider, 067 Ftrace.TracedSignalProvider 068 { 069 private static final Log warning = LogFactory.warning(FtraceController.class); 070 private static final Log fine = LogFactory.fine(FtraceController.class); 071 072 // ArrayList<SymbolRule> 073 private final List symRules = new ArrayList(); 074 private final List addrRules = new ArrayList(); 075 private final List sysRules = new ArrayList(); 076 private final List sigRules = new ArrayList(); 077 078 // Which symbols and addresses should yield a stack trace. 079 private HashSet tracePointStackTraceSet = new HashSet(); 080 private boolean stackTraceEverything = false; 081 082 public void stackTraceEverything() { 083 stackTraceEverything = true; 084 } 085 086 public boolean shouldStackTraceOnTracePoint(Object tracePoint) { 087 return stackTraceEverything 088 || tracePointStackTraceSet.contains(tracePoint); 089 } 090 091 public FtraceController() { } 092 093 public void gotSymRules(List rules) { 094 fine.log("Got " + rules.size() + " symbol rules."); 095 this.symRules.addAll(rules); 096 } 097 098 public void gotAddrRules(List rules) { 099 fine.log("Got " + rules.size() + " address rules."); 100 this.addrRules.addAll(rules); 101 } 102 103 public void gotSysRules(List rules) { 104 fine.log("Got " + rules.size() + " syscall rules."); 105 this.sysRules.addAll(rules); 106 } 107 108 public void gotSigRules(List rules) { 109 fine.log("Got " + rules.size() + " signal rules."); 110 this.sigRules.addAll(rules); 111 } 112 113 private Map computeWorkingSet(Task task, String what, 114 List rules, ArrayList candidates) 115 { 116 HashSet workingSet = new HashSet(); 117 HashSet stackTraceSet = new HashSet(); 118 119 for (Iterator it = rules.iterator(); it.hasNext(); ) { 120 final Rule rule = (Rule)it.next(); 121 fine.log("Considering " + what + " rule `" + rule + "'."); 122 if (!rule.apply(candidates, workingSet, stackTraceSet)) 123 warning.log("Rule", rule, "didn't match any", what); 124 } 125 126 // Apply the two sets. 127 Map ret = new HashMap(); 128 for (Iterator it = workingSet.iterator(); it.hasNext(); ) { 129 Object sysOrSig = it.next(); 130 ret.put(sysOrSig, 131 Boolean.valueOf(stackTraceEverything 132 || stackTraceSet.contains(sysOrSig))); 133 } 134 return ret; 135 } 136 137 // Syscall working and stack trace sets can be pre-computed for 138 // each task. This is in contrast to tracing rules, that are 139 // computed incrementally when DSOs are mapped. 140 public Map computeSyscallWorkingSet(Task task) { 141 SyscallTable syscallTable = task.getSyscallTable(); 142 long n = syscallTable.getNumSyscalls(); 143 ArrayList candidates = new ArrayList(); 144 for (long i = 0; i < n; ++i) 145 candidates.add(syscallTable.getSyscall(i)); 146 147 return computeWorkingSet(task, "syscall", sysRules, candidates); 148 } 149 150 // Compute signal working and stack trace sets. 151 public Map computeSignalWorkingSet(Task task) { 152 frysk.sys.Signal[] hostSignals 153 = frysk.sys.Signal.getHostSignalSet().toArray(); 154 SignalTable signalTable = task.getSignalTable(); 155 ArrayList candidates = new ArrayList(); 156 for (int i = 0; i < hostSignals.length; i++) 157 candidates.add(signalTable.get(hostSignals[i].intValue())); 158 159 return computeWorkingSet(task, "signal", sigRules, candidates); 160 } 161 162 private boolean isInterpOf(ObjectFile objf, String exe) 163 { 164 ObjectFile exef = ObjectFile.buildFromFile(exe); 165 java.io.File interpfn = exef.resolveInterp(); 166 java.io.File objffn = objf.getFilename(); 167 return objffn.equals(interpfn); 168 } 169 170 interface RuleHandler { 171 void applyTracePoint(Object tracePoint); 172 } 173 174 private void applySymbolRules(final Task task, final ObjectFile objf, 175 final List tracePoints, 176 final List rules, RuleHandler handler) 177 throws lib.dwfl.ElfException 178 { 179 String path = objf.getFilename().getPath(); 180 fine.log("Building working set for task", task, "and path", path); 181 182 // Skip the set if it's empty... 183 if (rules.isEmpty()) 184 return; 185 186 // Set<DwflSymbol>, incrementally built working set. 187 final Set workingSet = new HashSet(); 188 // Set<DwflSymbol>, incrementally built set of tracepoints 189 // that should stacktrace. 190 final Set stackTraceSet = new HashSet(); 191 192 // Loop through all the rules, and use them to build 193 // workingSet from candidates. 194 for (Iterator it = rules.iterator(); it.hasNext(); ) { 195 final SymbolRule rule = (SymbolRule)it.next(); 196 fine.log("Considering symbol rule " + rule + "."); 197 198 if (rule.fqid.sonameMatches(task, objf)) 199 rule.apply(tracePoints, workingSet, stackTraceSet); 200 } 201 202 // Finally, apply constructed working set. 203 fine.log("Applying working set for ", path); 204 tracePointStackTraceSet.addAll(stackTraceSet); 205 for (Iterator it = workingSet.iterator(); it.hasNext(); ) 206 handler.applyTracePoint(it.next()); 207 } 208 209 private void applyAddrRules(final Task task, final ObjectFile objf, 210 long bias, 211 final List rules, final Ftrace.Driver driver) 212 { 213 String path = objf.getFilename().getPath(); 214 fine.log("Building checkpoint set for task", task, "and path", path); 215 216 // Skip the set if it's empty... 217 if (rules.isEmpty()) 218 return; 219 220 // Set<Long>, incrementally built working set. 221 final Set workingSet = new HashSet(); 222 // Set<Long>, incrementally built set of tracepoints 223 // that should stacktrace. 224 final Set stackTraceSet = new HashSet(); 225 226 // Loop through all the rules, and use them to build 227 // workingSet from candidates. 228 for (Iterator it = rules.iterator(); it.hasNext(); ) { 229 final AddrRule rule = (AddrRule)it.next(); 230 final List candidate = new ArrayList(1); 231 candidate.add(new Long(rule.addr)); 232 233 fine.log("Considering addr rule", rule); 234 235 // MAIN is meta-soname meaning "main executable". 236 if ((rule.sonamePattern.pattern().equals("MAIN") 237 && task.getProc().getExeFile().getSysRootedPath().equals(path)) 238 || (rule.sonamePattern.pattern().equals("INTERP") 239 && isInterpOf(objf, task.getProc().getExeFile().getSysRootedPath())) 240 || rule.sonamePattern.matcher(objf.getSoname()).matches()) 241 { 242 rule.apply(candidate, workingSet, stackTraceSet); 243 } 244 } 245 246 // Finally, apply constructed working set. 247 fine.log("Applying checkpoint set for ", path); 248 tracePointStackTraceSet.addAll(stackTraceSet); 249 for (Iterator it = workingSet.iterator(); it.hasNext(); ) { 250 Long token = (Long)it.next(); 251 driver.traceAddress(task, token, bias, objf); 252 } 253 } 254 255 private List traceablesForModule(DwflModule module) { 256 257 Map symbolTable = SymbolFactory.getSymbolTable(module); 258 if (symbolTable.size() == 0) 259 // In that case we also know there are no PLT entries, 260 // because each PLT entry is defined on a symbol. 261 return null; 262 263 List traceables = new ArrayList(symbolTable.values()); 264 traceables.addAll(SymbolFactory.getPLTEntries(module, symbolTable)); 265 266 return traceables; 267 } 268 269 public void fileMapped(final Task task, ObjectFile objf, 270 DwflModule module, 271 final Ftrace.Driver driver) { 272 273 List traceables = traceablesForModule(module); 274 if (traceables == null) 275 return; 276 277 try { 278 applySymbolRules 279 (task, objf, traceables, symRules, 280 new RuleHandler() { 281 public void applyTracePoint(Object tracePoint) { 282 if (tracePoint instanceof PLTEntry) { 283 PLTEntry entry = (PLTEntry)tracePoint; 284 driver.tracePLTEntry(task, entry); 285 } else { 286 DwflSymbol symbol = (DwflSymbol)tracePoint; 287 driver.traceSymbol(task, symbol); 288 } 289 } 290 }); 291 292 ModuleElfBias eb = module.getElf(); 293 applyAddrRules(task, objf, eb.bias, addrRules, driver); 294 295 } catch (lib.dwfl.ElfException ee) { 296 ee.printStackTrace(); 297 } 298 } 299 300 public void fileUnmapped(final Task task, ObjectFile objf, 301 DwflModule module, 302 final Ftrace.Driver driver) { 303 304 List traceables = traceablesForModule(module); 305 if (traceables == null) 306 return; 307 308 driver.untrace(task, traceables); 309 } 310 311 }