Branch data Line data Source code
1 : : // Copyright (C) Andrew Tridgell 2002 (original file)
2 : : // Copyright (C) 2006-2011 Red Hat Inc. (systemtap changes)
3 : : //
4 : : // This program is free software; you can redistribute it and/or modify
5 : : // it under the terms of the GNU General Public License as published by
6 : : // the Free Software Foundation; either version 2 of the License, or
7 : : // (at your option) any later version.
8 : : //
9 : : // This program is distributed in the hope that it will be useful,
10 : : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : // GNU 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, see <http://www.gnu.org/licenses/>.
16 : :
17 : : #include "config.h"
18 : : #include "session.h"
19 : : #include "hash.h"
20 : : #include "util.h"
21 : :
22 : : #include <cstdlib>
23 : : #include <cstring>
24 : : #include <fstream>
25 : : #include <sstream>
26 : : #include <iomanip>
27 : : #include <cerrno>
28 : :
29 : : extern "C" {
30 : : #include <sys/types.h>
31 : : #include <sys/stat.h>
32 : : #include <unistd.h>
33 : : #include "mdfour.h"
34 : : }
35 : :
36 : : using namespace std;
37 : :
38 : :
39 : 10264 : class stap_hash
40 : : {
41 : : private:
42 : : struct mdfour md4;
43 : : std::ostringstream parm_stream;
44 : :
45 : : public:
46 [ + - ]: 880 : stap_hash() { start(); }
47 [ + - ][ + - ]: 10264 : stap_hash(const stap_hash &base) { md4 = base.md4; parm_stream << base.parm_stream.str(); }
[ + - ]
48 : :
49 : : void start();
50 : :
51 : : void add(const std::string& description, const unsigned char *buffer, size_t size);
52 : : template<typename T> void add(const std::string& d, const T& x);
53 : : void add(const std::string& d, const char *s) { add((const std::string&)d, (const unsigned char *)s, strlen(s)); }
54 : 35909 : void add(const std:: string& d, const std::string& s) { add(d, (const unsigned char *)s.c_str(), s.length()); }
55 : :
56 : : void add_path(const std::string& description, const std::string& path);
57 : :
58 : : void result(std::string& r);
59 : 10264 : std::string get_parms() { return parm_stream.str(); }
60 : : };
61 : :
62 : :
63 : : void
64 : 880 : stap_hash::start()
65 : : {
66 : 880 : mdfour_begin(&md4);
67 : 880 : }
68 : :
69 : :
70 : : void
71 : 35909 : stap_hash::add(const std::string& description, const unsigned char *buffer, size_t size)
72 : : {
73 : 35909 : parm_stream << description << buffer << endl;
74 : 35909 : mdfour_update(&md4, buffer, size);
75 : 35909 : }
76 : :
77 : :
78 : : template <typename T> void
79 : 38738 : stap_hash::add(const std::string& d, const T& x)
80 : : {
81 : 38738 : parm_stream << d << x << endl;
82 : 38738 : mdfour_update(&md4, (const unsigned char *)&x, sizeof(x));
83 : 38738 : }
84 : :
85 : :
86 : : void
87 : 15299 : stap_hash::add_path(const std::string& description, const std::string& path)
88 : : {
89 : : struct stat st;
90 : 15299 : memset (&st, 0, sizeof(st));
91 : :
92 [ + - ][ + + ]: 15299 : if (stat(path.c_str(), &st) != 0)
93 : 2281 : st.st_size = st.st_mtime = -1;
94 : :
95 [ + - ][ + - ]: 15299 : add(description + "Path: ", path);
[ + - ]
96 [ + - ][ + - ]: 15299 : add(description + "Size: ", st.st_size);
[ + - ]
97 [ + - ][ + - ]: 15299 : add(description + "Timestamp: ", st.st_mtime);
[ + - ]
98 : 15299 : }
99 : :
100 : :
101 : : void
102 : 10264 : stap_hash::result(string& r)
103 : : {
104 [ + - ]: 10264 : ostringstream rstream;
105 : : unsigned char sum[16];
106 : :
107 [ + - ]: 10264 : mdfour_update(&md4, NULL, 0);
108 [ + - ]: 10264 : mdfour_result(&md4, sum);
109 : :
110 [ + + ]: 174488 : for (int i=0; i<16; i++)
111 : : {
112 [ + - ][ + - ]: 164224 : rstream << hex << setfill('0') << setw(2) << (unsigned)sum[i];
[ + - ][ + - ]
113 : : }
114 [ + - ][ + - ]: 10264 : rstream << "_" << setw(0) << dec << (unsigned)md4.totalN;
[ + - ][ + - ]
115 [ + - ][ + - ]: 10264 : r = rstream.str();
[ + - ][ + - ]
116 : 10264 : }
117 : :
118 : 10264 : void create_hash_log(const string &type_str, const string &parms, const string &result, const string &hash_log_path)
119 : : {
120 [ + - ]: 10264 : ofstream log_file;
121 : : time_t rawtime;
122 : 10264 : time ( &rawtime );
123 [ + - ]: 10264 : string time_str(ctime (&rawtime));
124 : :
125 [ + - ][ + - ]: 10264 : log_file.open(hash_log_path.c_str());
126 [ + - ][ + - ]: 10264 : log_file << "[" << time_str.substr(0,time_str.length()-1); // erase terminated '\n'
[ + - ][ + - ]
[ + - ]
127 [ + - ][ + - ]: 10264 : log_file << "] " << type_str << ":" << endl;
[ + - ][ + - ]
128 [ + - ][ + - ]: 10264 : log_file << parms << endl;
129 [ + - ][ + - ]: 10264 : log_file << _("result:") << result << endl;
[ + - ]
130 [ + - ][ + - ]: 10264 : log_file.close();
[ + - ]
131 : 10264 : }
132 : :
133 : : static const stap_hash&
134 : 10264 : get_base_hash (systemtap_session& s)
135 : : {
136 [ + + ]: 10264 : if (s.base_hash)
137 : 9384 : return *s.base_hash;
138 : :
139 [ + - ]: 880 : s.base_hash = new stap_hash();
140 : 880 : stap_hash& h = *s.base_hash;
141 : :
142 : : // Hash kernel release and arch.
143 [ + - ][ + - ]: 880 : h.add("Kernel Release: ", s.kernel_release);
[ + - ]
144 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree ", s.kernel_build_tree);
[ + - ]
145 [ + - ][ + - ]: 880 : h.add("Architecture: ", s.architecture);
[ + - ]
146 : :
147 : : // Hash a few kernel version/build-id files too
148 : : // (useful for kernel developers reusing a single source tree)
149 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree .config ", s.kernel_build_tree + "/.config");
[ + - ][ + - ]
[ + - ]
150 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree .version ", s.kernel_build_tree + "/.version");
[ + - ][ + - ]
[ + - ]
151 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree compile.h ", s.kernel_build_tree + "/include/linux/compile.h");
[ + - ][ + - ]
[ + - ]
152 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree version.h ", s.kernel_build_tree + "/include/linux/version.h");
[ + - ][ + - ]
[ + - ]
153 [ + - ][ + - ]: 880 : h.add_path("Kernel Build Tree utsrelease.h ", s.kernel_build_tree + "/include/linux/utsrelease.h");
[ + - ][ + - ]
[ + - ]
154 : :
155 : : // Hash runtime path (that gets added in as "-R path").
156 [ + - ][ + - ]: 880 : h.add_path("Runtime ", s.runtime_path);
[ + - ]
157 [ + - ][ + - ]: 880 : h.add_path("Runtime transport ", s.runtime_path + "/transport");
[ + - ][ + - ]
[ + - ]
158 [ + - ][ + - ]: 880 : h.add_path("Runtime unwind ", s.runtime_path + "/unwind");
[ + - ][ + - ]
[ + - ]
159 : : h.add_path("Runtime sub ", s.runtime_path +
160 [ + - ][ - + ]: 880 : (s.runtime_usermode_p() ? "/dyninst" : "/linux"));
[ + - ][ + - ]
[ + - ][ + - ]
161 : :
162 : : // Hash compiler path, size, and mtime. We're just going to assume
163 : : // we'll be using gcc. XXX: getting kbuild to spit out out would be
164 : : // better, especially since this is fooled by ccache.
165 [ + - ][ + - ]: 880 : h.add_path("Compiler ", find_executable("gcc"));
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
166 : :
167 : : // Hash the systemtap size and mtime. We could use VERSION/DATE,
168 : : // but when developing systemtap that doesn't work well (since you
169 : : // can compile systemtap multiple times in 1 day). Since we don't
170 : : // know exactly where we're getting run from, we'll use
171 : : // /proc/self/exe (and we resolve it ourselves to help valgrind).
172 [ + - ][ + - ]: 880 : h.add_path("Systemtap ", get_self_path());
[ + - ][ + - ]
[ + - ]
173 : :
174 : 10264 : return h;
175 : : }
176 : :
177 : :
178 : : static bool
179 : 10264 : create_hashdir (systemtap_session& s, const string& result, string& hashdir)
180 : : {
181 : 10264 : int nlevels = 1;
182 : :
183 : : // Use a N level subdir for the cache path to reduce the impact on
184 : : // filesystems which are slow for large directories. Let N be adjustable.
185 : 10264 : const char *s_n = getenv("SYSTEMTAP_NLEVELS");
186 [ - + ]: 10264 : if (s_n)
187 : : {
188 : 0 : nlevels = atoi(s_n);
189 [ # # ]: 0 : if (nlevels < 1) nlevels = 1;
190 [ # # ]: 0 : if (nlevels > 8) nlevels = 8;
191 : : }
192 : :
193 : 10264 : hashdir = s.cache_path;
194 : :
195 [ + + ]: 20528 : for (int i = 0; i < nlevels; i++)
196 : : {
197 [ + - ][ + - ]: 10264 : hashdir += string("/") + result[i*2] + result[i*2 + 1];
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
198 [ - + ]: 10264 : if (create_dir(hashdir.c_str()) != 0)
199 : : {
200 [ # # ][ # # ]: 0 : s.print_warning("failed to create cache directory (\"" + hashdir + "\") " + strerror(errno) + ", disabling cache support");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
201 : 0 : s.use_cache = s.use_script_cache = false;
202 : 0 : return false;
203 : : }
204 : : }
205 : 10264 : return true;
206 : : }
207 : :
208 : :
209 : : void
210 : 814 : find_script_hash (systemtap_session& s, const string& script)
211 : : {
212 [ + - ][ + - ]: 814 : stap_hash h(get_base_hash(s));
213 : :
214 : : // Hash getuid. This really shouldn't be necessary (since who you
215 : : // are doesn't change the generated output), but the hash gets used
216 : : // as the module name. If two different users try to run the same
217 : : // script at the same time, we need something to differentiate the
218 : : // module name.
219 [ + - ][ + - ]: 814 : h.add("UID: ", getuid());
[ + - ]
220 : :
221 : : // Hash user-specified arguments (that change the generated module).
222 [ + - ][ + - ]: 814 : h.add("Bulk Mode (-b): ", s.bulk_mode);
[ + - ]
223 [ + - ][ + - ]: 814 : h.add("Timing (-t): ", s.timing);
[ + - ]
224 [ + - ][ + - ]: 814 : h.add("Prologue Searching (-P): ", s.prologue_searching);
[ + - ]
225 [ + - ][ + - ]: 814 : h.add("Skip Badvars (--skip-badvars): ", s.skip_badvars);
[ + - ]
226 [ + - ][ + - ]: 814 : h.add("Privilege (--privilege): ", s.privilege);
[ + - ]
227 [ + - ][ + - ]: 814 : h.add("Compatible (--compatible): ", s.compatible);
[ + - ]
228 [ + - ][ + - ]: 814 : h.add("Omit Werror (undocumented): ", s.omit_werror);
[ + - ]
229 [ + - ][ + - ]: 814 : h.add("Prologue Searching (-P): ", s.prologue_searching);
[ + - ]
230 [ + - ][ + - ]: 814 : h.add("Error suppression (--suppress-handler-errors): ", s.suppress_handler_errors);
[ + - ]
231 [ + - ][ + - ]: 814 : h.add("Suppress Time Limits (--suppress-time-limits): ", s.suppress_time_limits);
[ + - ]
232 [ + + ]: 903 : for (unsigned i = 0; i < s.c_macros.size(); i++)
233 [ + - ][ + - ]: 89 : h.add("Macros: ", s.c_macros[i]);
[ + - ]
234 : :
235 : : // Add any custom kbuild flags (-B)
236 [ + + ]: 1614 : for (unsigned i = 0; i < s.kbuildflags.size(); i++)
237 [ + - ][ + - ]: 800 : h.add("Kbuildflags: ", s.kbuildflags[i]);
[ + - ]
238 : :
239 : : // Add any custom --modinfo strings
240 [ + + ]: 1615 : for (unsigned i = 0; i < s.modinfos.size(); i++)
241 [ + - ][ + - ]: 801 : h.add("MODULE_INFO: ", s.modinfos[i]);
[ + - ]
242 : :
243 : : // -d MODULE
244 [ + - ][ + + ]: 2706 : for (set<string>::iterator it = s.unwindsym_modules.begin();
245 [ + - ]: 1353 : it != s.unwindsym_modules.end();
246 : : it++)
247 [ + - ][ + - ]: 539 : h.add_path("Unwindsym Modules ", *it);
[ + - ]
248 : :
249 : : // Add the build id of each module
250 [ + - ][ + - ]: 4562 : for(vector<string>::iterator it = s.build_ids.begin();
[ + - ][ + + ]
251 [ + - ]: 2281 : it != s.build_ids.end();
252 : : it++)
253 [ + - ][ + - ]: 1467 : h.add("Build ID: ", *it);
[ + - ]
254 : :
255 : : // Add in pass 2 script output.
256 [ + - ][ + - ]: 814 : h.add("Script:\n", script);
[ + - ]
257 : :
258 : : // Get the directory path to store our cached script
259 [ + - ][ + - ]: 814 : string result, hashdir;
260 [ + - ]: 814 : h.result(result);
261 [ + - ][ - + ]: 814 : if (!create_hashdir(s, result, hashdir))
262 : 814 : return;
263 : :
264 : : // Update module name to be 'stap_{hash start}'. '{hash start}'
265 : : // must not be too long. This shouldn't happen, since the maximum
266 : : // size of a hash is 32 fixed chars + 1 (for the '_') + a max of 11.
267 [ + - ][ + - ]: 814 : s.module_name = "stap_" + result;
[ + - ]
268 [ + - ][ - + ]: 814 : if (s.module_name.size() >= (MODULE_NAME_LEN - 1))
269 [ # # ]: 0 : s.module_name.resize(MODULE_NAME_LEN - 1);
270 : :
271 : : // 'ccache' would use a hash path of something like:
272 : : // s.hash_path = hashdir + "/" + result.substr(nlevels);
273 : : // which would look like:
274 : : // ~/.stap_cache/A/B/CDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX
275 : : //
276 : : // We're using the following so that the module can be used straight
277 : : // from the cache if desired. This ends up looking like this:
278 : : // ~/.stap_cache/A/B/stap_ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX.ko
279 [ + - ][ + - ]: 814 : s.hash_path = hashdir + "/" + s.module_filename();
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
280 : :
281 : : // Update C source name with new module_name.
282 [ + - ][ + - ]: 814 : s.translated_source = string(s.tmpdir) + "/" + s.module_name + "_src.c";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
283 : : create_hash_log(string("script_hash"), h.get_parms(), result,
284 [ + - ][ + - ]: 814 : hashdir + "/" + s.module_name + "_hash.log");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ + - ]
[ - + ][ + - ]
[ + - ]
285 : : }
286 : :
287 : :
288 : : void
289 : 622 : find_stapconf_hash (systemtap_session& s)
290 : : {
291 [ + - ][ + - ]: 622 : stap_hash h(get_base_hash(s));
292 : :
293 : : // Add any custom kbuild flags
294 [ + + ]: 1235 : for (unsigned i = 0; i < s.kbuildflags.size(); i++)
295 [ + - ][ + - ]: 613 : h.add("Kbuildflags: ", s.kbuildflags[i]);
[ + - ]
296 : :
297 : : // Get the directory path to store our cached stapconf parameters
298 [ + - ][ + - ]: 622 : string result, hashdir;
299 [ + - ]: 622 : h.result(result);
300 [ + - ][ - + ]: 622 : if (!create_hashdir(s, result, hashdir))
301 : 622 : return;
302 : :
303 [ + - ][ + - ]: 622 : s.stapconf_name = "stapconf_" + result + ".h";
[ + - ][ + - ]
[ + - ]
304 [ + - ][ + - ]: 622 : s.stapconf_path = hashdir + "/" + s.stapconf_name;
[ + - ][ + - ]
[ + - ]
305 : : create_hash_log(string("stapconf_hash"), h.get_parms(), result,
306 [ + - ][ + - ]: 622 : hashdir + "/stapconf_" + result + "_hash.log");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ + - ]
[ - + ][ + - ]
[ + - ]
307 : : }
308 : :
309 : :
310 : : string
311 : 4200 : find_tracequery_hash (systemtap_session& s, const string& header)
312 : : {
313 [ + - ][ + - ]: 4200 : stap_hash h(get_base_hash(s));
314 : :
315 : : // Add the tracepoint header to the computed hash
316 [ + - ][ + - ]: 4200 : h.add_path("Header ", header);
[ + - ]
317 : :
318 : : // Add any custom kbuild flags
319 [ + + ]: 8400 : for (unsigned i = 0; i < s.kbuildflags.size(); i++)
320 [ + - ][ + - ]: 4200 : h.add("Kbuildflags: ", s.kbuildflags[i]);
[ + - ]
321 : :
322 : : // Get the directory path to store our cached module
323 [ + - ][ + - ]: 4200 : string result, hashdir;
324 [ + - ]: 4200 : h.result(result);
325 [ + - ][ - + ]: 4200 : if (!create_hashdir(s, result, hashdir))
326 [ # # ]: 0 : return ""; // XXX: as opposed to throwing an exception?
327 : :
328 : : create_hash_log(string("tracequery_hash"), h.get_parms(), result,
329 [ + - ][ + - ]: 4200 : hashdir + "/tracequery_" + result + "_hash.log");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
330 [ + - ][ + - ]: 4200 : return hashdir + "/tracequery_" + result + ".o";
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
331 : : }
332 : :
333 : :
334 : : string
335 : 4628 : find_typequery_hash (systemtap_session& s, const string& name)
336 : : {
337 [ + - ][ + - ]: 4628 : stap_hash h(get_base_hash(s));
338 : :
339 : : // Add the typequery name to distinguish the hash
340 [ + - ][ + - ]: 4628 : h.add("Typequery Name: ", name);
[ + - ]
341 : :
342 [ + - ][ + + ]: 4628 : if (name[0] == 'k')
343 : : // Add any custom kbuild flags
344 [ + + ]: 9248 : for (unsigned i = 0; i < s.kbuildflags.size(); i++)
345 [ + - ][ + - ]: 4624 : h.add("Kbuildflags: ", s.kbuildflags[i]);
[ + - ]
346 : :
347 : : // Get the directory path to store our cached module
348 [ + - ][ + - ]: 4628 : string result, hashdir;
349 [ + - ]: 4628 : h.result(result);
350 [ + - ][ - + ]: 4628 : if (!create_hashdir(s, result, hashdir))
351 [ # # ]: 0 : return "";
352 : :
353 : : create_hash_log(string("typequery_hash"), h.get_parms(), result,
354 [ + - ][ + - ]: 4628 : hashdir + "/typequery_" + result + "_hash.log");
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
355 : : return hashdir + "/typequery_" + result
356 [ + - ][ + - ]: 4628 : + (name[0] == 'k' ? ".ko" : ".so");
[ + - ][ + + ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
357 : : }
358 : :
359 : :
360 : : string
361 : 0 : find_uprobes_hash (systemtap_session& s)
362 : : {
363 [ # # ][ # # ]: 0 : stap_hash h(get_base_hash(s));
364 : :
365 : : // Hash runtime uprobes paths
366 [ # # ][ # # ]: 0 : h.add_path("Uprobes Runtime Path /uprobes ", s.runtime_path + "/linux/uprobes");
[ # # ][ # # ]
[ # # ]
367 [ # # ][ # # ]: 0 : h.add_path("Uprobes Runtime Path /uprobes2 ", s.runtime_path + "/linux/uprobes2");
[ # # ][ # # ]
[ # # ]
368 : :
369 : : // Add any custom kbuild flags
370 [ # # ]: 0 : for (unsigned i = 0; i < s.kbuildflags.size(); i++)
371 [ # # ][ # # ]: 0 : h.add("Kbuildflags: ", s.kbuildflags[i]);
[ # # ]
372 : :
373 : : // Add any custom --modinfo strings
374 [ # # ]: 0 : for (unsigned i = 0; i < s.modinfos.size(); i++)
375 [ # # ][ # # ]: 0 : h.add("MODULE_INFO: ", s.modinfos[i]);
[ # # ]
376 : :
377 : : // Get the directory path to store our cached module
378 [ # # ][ # # ]: 0 : string result, hashdir;
379 [ # # ]: 0 : h.result(result);
380 [ # # ][ # # ]: 0 : if (!create_hashdir(s, result, hashdir))
381 [ # # ]: 0 : return "";
382 : :
383 : : create_hash_log(string("uprobes_hash"), h.get_parms(), result,
384 [ # # ][ # # ]: 0 : hashdir + "/uprobes_" + result + "_hash.log");
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
385 [ # # ][ # # ]: 0 : return hashdir + "/uprobes_" + result;
[ # # ][ # # ]
[ # # ][ # # ]
386 [ + - ][ + - ]: 7242 : }
387 : :
388 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|