]> sourceware.org Git - systemtap.git/blame - hash.cxx
PR13156: More verbose hash log output
[systemtap.git] / hash.cxx
CommitLineData
1b78aef5 1// Copyright (C) Andrew Tridgell 2002 (original file)
1e6e9ec1 2// Copyright (C) 2006-2011 Red Hat Inc. (systemtap changes)
dff50e09 3//
1b78aef5
DS
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.
dff50e09 8//
1b78aef5
DS
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.
dff50e09 13//
1b78aef5 14// You should have received a copy of the GNU General Public License
e8daaf60 15// along with this program. If not, see <http://www.gnu.org/licenses/>.
1b78aef5
DS
16
17#include "config.h"
18#include "session.h"
19#include "hash.h"
20#include "util.h"
3b579393
FCE
21
22#include <cstdlib>
dd936721
JS
23#include <cstring>
24#include <fstream>
1b78aef5
DS
25#include <sstream>
26#include <iomanip>
27#include <cerrno>
28
29extern "C" {
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <unistd.h>
dd936721 33#include "mdfour.h"
1b78aef5
DS
34}
35
36using namespace std;
37
dd936721
JS
38
39class hash
40{
41private:
42 struct mdfour md4;
43 std::ostringstream parm_stream;
44
45public:
46 hash() { start(); }
47 hash(const hash &base) { md4 = base.md4; parm_stream << base.parm_stream.str(); }
48
49 void start();
50
333040ca
CM
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 void add(const std:: string& d, const std::string& s) { add(d, (const unsigned char *)s.c_str(), s.length()); }
9beca2c0 55
333040ca 56 void add_path(const std::string& description, const std::string& path);
dd936721
JS
57
58 void result(std::string& r);
178b5ebc 59 std::string get_parms() { return parm_stream.str(); }
dd936721
JS
60};
61
62
1b78aef5
DS
63void
64hash::start()
65{
66 mdfour_begin(&md4);
67}
68
69
70void
333040ca 71hash::add(const std::string& description, const unsigned char *buffer, size_t size)
1b78aef5 72{
333040ca
CM
73 // If the string is longer than 80 and it is not a path, only
74 // put the last 80 characters from the string into the hash log.
75 // string stripped_buffer = lex_cast_qstring(buffer);
76 if(size > 80 && buffer[0] != '/')
77 parm_stream << description << "..." << lex_cast_qstring(buffer+(size-80)) << endl;
78 else
79 parm_stream << description << lex_cast_qstring(buffer) << endl;
80
1b78aef5
DS
81 mdfour_update(&md4, buffer, size);
82}
83
84
9beca2c0 85template <typename T> void
333040ca 86hash::add(const std::string& d, const T& x)
9beca2c0 87{
333040ca 88 parm_stream << d << x << endl;
9beca2c0
JS
89 mdfour_update(&md4, (const unsigned char *)&x, sizeof(x));
90}
91
92
2a8c27f6 93void
333040ca 94hash::add_path(const std::string& description, const std::string& path)
2a8c27f6
JS
95{
96 struct stat st;
e7899657 97 memset (&st, 0, sizeof(st));
2a8c27f6 98
413c55ed 99 if (stat(path.c_str(), &st) != 0)
9a193b06
JS
100 st.st_size = st.st_mtime = -1;
101
333040ca
CM
102 add(description + "Path: ", path);
103 add(description + "Size: ", st.st_size);
104 add(description + "Timestamp: ", st.st_mtime);
2a8c27f6
JS
105}
106
107
1b78aef5
DS
108void
109hash::result(string& r)
110{
111 ostringstream rstream;
112 unsigned char sum[16];
113
114 mdfour_update(&md4, NULL, 0);
115 mdfour_result(&md4, sum);
116
117 for (int i=0; i<16; i++)
118 {
119 rstream << hex << setfill('0') << setw(2) << (unsigned)sum[i];
120 }
121 rstream << "_" << setw(0) << dec << (unsigned)md4.totalN;
122 r = rstream.str();
123}
124
0d1ad607
WH
125void create_hash_log(const string &type_str, const string &parms, const string &result, const string &hash_log_path)
126{
127 ofstream log_file;
128 time_t rawtime;
129 time ( &rawtime );
130 string time_str(ctime (&rawtime));
131
132 log_file.open(hash_log_path.c_str());
133 log_file << "[" << time_str.substr(0,time_str.length()-1); // erase terminated '\n'
178b5ebc
JS
134 log_file << "] " << type_str << ":" << endl;
135 log_file << parms << endl;
659d42ce 136 log_file << _("result:") << result << endl;
0d1ad607
WH
137 log_file.close();
138}
1b78aef5 139
9b3c54b2
JS
140static const hash&
141get_base_hash (systemtap_session& s)
1b78aef5 142{
9b3c54b2
JS
143 if (s.base_hash)
144 return *s.base_hash;
145
146 s.base_hash = new hash();
147 hash& h = *s.base_hash;
148
5c54d49e 149 // Hash kernel release and arch.
333040ca
CM
150 h.add("Kernel Release: ", s.kernel_release);
151 h.add_path("Kernel Build Tree ", s.kernel_build_tree);
152 h.add("Architecture: ", s.architecture);
5c54d49e 153
2a8c27f6
JS
154 // Hash a few kernel version/build-id files too
155 // (useful for kernel developers reusing a single source tree)
333040ca
CM
156 h.add_path("Kernel Build Tree .config ", s.kernel_build_tree + "/.config");
157 h.add_path("Kernel Build Tree .version ", s.kernel_build_tree + "/.version");
158 h.add_path("Kernel Build Tree compile.h ", s.kernel_build_tree + "/include/linux/compile.h");
159 h.add_path("Kernel Build Tree version.h ", s.kernel_build_tree + "/include/linux/version.h");
160 h.add_path("Kernel Build Tree utsrelease.h ", s.kernel_build_tree + "/include/linux/utsrelease.h");
2a8c27f6 161
5c54d49e 162 // Hash runtime path (that gets added in as "-R path").
333040ca 163 h.add_path("Runtime ", s.runtime_path);
5c54d49e
JS
164
165 // Hash compiler path, size, and mtime. We're just going to assume
166 // we'll be using gcc. XXX: getting kbuild to spit out out would be
413c55ed 167 // better, especially since this is fooled by ccache.
333040ca 168 h.add_path("Compiler ", find_executable("gcc"));
5c54d49e
JS
169
170 // Hash the systemtap size and mtime. We could use VERSION/DATE,
171 // but when developing systemtap that doesn't work well (since you
172 // can compile systemtap multiple times in 1 day). Since we don't
173 // know exactly where we're getting run from, we'll use
174 // /proc/self/exe.
413c55ed 175 // XXX well almost exactly -- valgrind throws this off
333040ca 176 h.add_path("Systemtap ", "/proc/self/exe");
9b3c54b2
JS
177
178 return h;
5c54d49e
JS
179}
180
181
182static bool
183create_hashdir (systemtap_session& s, const string& result, string& hashdir)
184{
185 int nlevels = 1;
186
187 // Use a N level subdir for the cache path to reduce the impact on
188 // filesystems which are slow for large directories. Let N be adjustable.
189 const char *s_n = getenv("SYSTEMTAP_NLEVELS");
190 if (s_n)
1b78aef5
DS
191 {
192 nlevels = atoi(s_n);
193 if (nlevels < 1) nlevels = 1;
194 if (nlevels > 8) nlevels = 8;
195 }
196
5c54d49e
JS
197 hashdir = s.cache_path;
198
199 for (int i = 0; i < nlevels; i++)
200 {
201 hashdir += string("/") + result[i*2] + result[i*2 + 1];
202 if (create_dir(hashdir.c_str()) != 0)
203 {
204 if (! s.suppress_warnings)
46a1a151
JS
205 cerr << _F("Warning: failed to create cache directory (\"%s\") %s, disabling cache support",
206 hashdir.c_str(), strerror(errno)) << endl;
63d530ab 207 s.use_cache = s.use_script_cache = false;
5c54d49e
JS
208 return false;
209 }
210 }
211 return true;
212}
213
214
9b3c54b2
JS
215void
216find_script_hash (systemtap_session& s, const string& script)
5c54d49e 217{
9b3c54b2 218 hash h(get_base_hash(s));
5c54d49e
JS
219 struct stat st;
220
1b78aef5
DS
221 // Hash getuid. This really shouldn't be necessary (since who you
222 // are doesn't change the generated output), but the hash gets used
223 // as the module name. If two different users try to run the same
224 // script at the same time, we need something to differentiate the
225 // module name.
333040ca 226 h.add("UID: ", getuid());
1b78aef5 227
1b78aef5 228 // Hash user-specified arguments (that change the generated module).
333040ca
CM
229 h.add("Bulk Mode (-b): ", s.bulk_mode); // '-b'
230 h.add("Timing (-t): ", s.timing); // '-t'
231 h.add("Prologue Searching (-P): ", s.prologue_searching); // '-P'
232 h.add("Ignore Vmlinux (--ignore-vmlinux): ", s.ignore_vmlinux); // --ignore-vmlinux
233 h.add("Ignore Dwarf (--ignore-dwarf): ", s.ignore_dwarf); // --ignore-dwarf
234 h.add("Consult Symtab (--kelf, --kmap): ", s.consult_symtab); // --kelf, --kmap
235 h.add("Skip Badvars (--skip-badvars): ", s.skip_badvars); // --skip-badvars
236 h.add("Unprivileged (--unprivileged): ", s.unprivileged); // --unprivileged
237 h.add("Compatible (--compatible): ", s.compatible); // --compatible
238 h.add("Omit Werror (undocumented): ", s.omit_werror); // undocumented, evil
5f0a03a6
JK
239 if (!s.kernel_symtab_path.empty()) // --kmap
240 {
333040ca 241 h.add("Kernel Symtab Path: ", s.kernel_symtab_path);
5f0a03a6
JK
242 if (stat(s.kernel_symtab_path.c_str(), &st) == 0)
243 {
244 // NB: stat of /proc/kallsyms always returns size=0, mtime=now...
245 // which is a good reason to use the default /boot/System.map-2.6.xx
246 // instead.
333040ca
CM
247 h.add("Kernel Symtab Size: ", st.st_size);
248 h.add("Kernel Symtab Timestamp: ", st.st_mtime);
5f0a03a6
JK
249 }
250 }
1b78aef5 251 for (unsigned i = 0; i < s.macros.size(); i++)
333040ca 252 h.add("Macros: ", s.macros[i]);
1b78aef5 253
4569f6bb 254 // Add any custom kbuild flags (-B)
1392896d 255 for (unsigned i = 0; i < s.kbuildflags.size(); i++)
333040ca 256 h.add("Kbuildflags: ", s.kbuildflags[i]);
1392896d 257
a7f52597
FCE
258 // -d MODULE
259 for (set<string>::iterator it = s.unwindsym_modules.begin();
260 it != s.unwindsym_modules.end();
261 it++)
333040ca 262 h.add_path("Unwindsym Modules ", *it);
ecd129af
CM
263
264 // Add the build id of each module
265 for(vector<string>::iterator it = s.build_ids.begin();
266 it != s.build_ids.end();
267 it++)
333040ca 268 h.add("Build ID: ", *it);
a7f52597 269
1b78aef5 270 // Add in pass 2 script output.
333040ca 271 h.add("Script: ", script);
1b78aef5 272
5c54d49e
JS
273 // Get the directory path to store our cached script
274 string result, hashdir;
1b78aef5 275 h.result(result);
5c54d49e
JS
276 if (!create_hashdir(s, result, hashdir))
277 return;
1b78aef5
DS
278
279 // Update module name to be 'stap_{hash start}'. '{hash start}'
280 // must not be too long. This shouldn't happen, since the maximum
281 // size of a hash is 32 fixed chars + 1 (for the '_') + a max of 11.
282 s.module_name = "stap_" + result;
283 if (s.module_name.size() >= (MODULE_NAME_LEN - 1))
284 s.module_name.resize(MODULE_NAME_LEN - 1);
285
286 // 'ccache' would use a hash path of something like:
287 // s.hash_path = hashdir + "/" + result.substr(nlevels);
288 // which would look like:
289 // ~/.stap_cache/A/B/CDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX
290 //
291 // We're using the following so that the module can be used straight
292 // from the cache if desired. This ends up looking like this:
293 // ~/.stap_cache/A/B/stap_ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX.ko
294 s.hash_path = hashdir + "/" + s.module_name + ".ko";
295
296 // Update C source name with new module_name.
297 s.translated_source = string(s.tmpdir) + "/" + s.module_name + ".c";
0d1ad607
WH
298 create_hash_log(string("script_hash"), h.get_parms(), result,
299 hashdir + "/" + s.module_name + "_hash.log");
1b78aef5 300}
73267b89 301
5c54d49e 302
9b3c54b2
JS
303void
304find_stapconf_hash (systemtap_session& s)
5c54d49e 305{
9b3c54b2 306 hash h(get_base_hash(s));
5c54d49e 307
4569f6bb
JS
308 // Add any custom kbuild flags
309 for (unsigned i = 0; i < s.kbuildflags.size(); i++)
333040ca 310 h.add("Kbuildflags: ", s.kbuildflags[i]);
5c54d49e
JS
311
312 // Get the directory path to store our cached stapconf parameters
313 string result, hashdir;
314 h.result(result);
315 if (!create_hashdir(s, result, hashdir))
316 return;
317
de0db58a
JS
318 s.stapconf_name = "stapconf_" + result + ".h";
319 s.stapconf_path = hashdir + "/" + s.stapconf_name;
0d1ad607
WH
320 create_hash_log(string("stapconf_hash"), h.get_parms(), result,
321 hashdir + "/stapconf_" + result + "_hash.log");
5c54d49e
JS
322}
323
324
a2639cb7 325string
55e50c24 326find_tracequery_hash (systemtap_session& s, const vector<string>& headers)
b278033a 327{
9b3c54b2 328 hash h(get_base_hash(s));
b278033a 329
55e50c24
JS
330 // Add the tracepoint headers to the computed hash
331 for (size_t i = 0; i < headers.size(); ++i)
333040ca 332 h.add_path("Headers ", headers[i]);
b278033a 333
4569f6bb
JS
334 // Add any custom kbuild flags
335 for (unsigned i = 0; i < s.kbuildflags.size(); i++)
333040ca 336 h.add("Kbuildflags: ", s.kbuildflags[i]);
4569f6bb 337
b278033a
JS
338 // Get the directory path to store our cached module
339 string result, hashdir;
340 h.result(result);
341 if (!create_hashdir(s, result, hashdir))
a2639cb7 342 return "";
b278033a 343
0d1ad607
WH
344 create_hash_log(string("tracequery_hash"), h.get_parms(), result,
345 hashdir + "/tracequery_" + result + "_hash.log");
a2639cb7 346 return hashdir + "/tracequery_" + result + ".ko";
b278033a
JS
347}
348
1f329b5e 349
a2639cb7
JS
350string
351find_typequery_hash (systemtap_session& s, const string& name)
1f329b5e 352{
9b3c54b2 353 hash h(get_base_hash(s));
1f329b5e
JS
354
355 // Add the typequery name to distinguish the hash
333040ca 356 h.add("Typequery Name: ", name);
1f329b5e 357
4569f6bb
JS
358 if (name[0] == 'k')
359 // Add any custom kbuild flags
360 for (unsigned i = 0; i < s.kbuildflags.size(); i++)
333040ca 361 h.add("Kbuildflags: ", s.kbuildflags[i]);
4569f6bb 362
1f329b5e
JS
363 // Get the directory path to store our cached module
364 string result, hashdir;
365 h.result(result);
366 if (!create_hashdir(s, result, hashdir))
a2639cb7 367 return "";
1f329b5e 368
0d1ad607
WH
369 create_hash_log(string("typequery_hash"), h.get_parms(), result,
370 hashdir + "/typequery_" + result + "_hash.log");
a2639cb7 371 return hashdir + "/typequery_" + result
1f329b5e
JS
372 + (name[0] == 'k' ? ".ko" : ".so");
373}
374
7d26ee02
JS
375
376string
377find_uprobes_hash (systemtap_session& s)
378{
379 hash h(get_base_hash(s));
380
381 // Hash runtime uprobes paths
333040ca
CM
382 h.add_path("Uprobes Runtime Path /uprobes ", s.runtime_path + "/uprobes");
383 h.add_path("Uprobes Runtime Path /uprobes2 ", s.runtime_path + "/uprobes2");
7d26ee02
JS
384
385 // Add any custom kbuild flags
386 for (unsigned i = 0; i < s.kbuildflags.size(); i++)
333040ca 387 h.add("Kbuildflags: ", s.kbuildflags[i]);
7d26ee02
JS
388
389 // Get the directory path to store our cached module
390 string result, hashdir;
391 h.result(result);
392 if (!create_hashdir(s, result, hashdir))
393 return "";
394
395 create_hash_log(string("uprobes_hash"), h.get_parms(), result,
396 hashdir + "/uprobes_" + result + "_hash.log");
397 return hashdir + "/uprobes_" + result;
398}
399
73267b89 400/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.124975 seconds and 5 git commands to generate.