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