]>
sourceware.org Git - systemtap.git/blob - hash.cxx
1 // Copyright (C) Andrew Tridgell 2002 (original file)
2 // Copyright (C) 2006-2008 Red Hat Inc. (systemtap changes)
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.
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.
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.
29 #include <sys/types.h>
44 hash::add(const unsigned char *buffer
, size_t size
)
46 parm_stream
<< "," << buffer
;
47 mdfour_update(&md4
, buffer
, size
);
52 hash::add_file(const std::string
& filename
)
56 if (stat(filename
.c_str(), &st
) != 0)
57 st
.st_size
= st
.st_mtime
= -1;
67 string parms_str
= parm_stream
.str();
70 if (!parms_str
.empty())
71 parms_str
.erase(parms_str
.begin()); // skip leading ","
76 hash::result(string
& r
)
78 ostringstream rstream
;
79 unsigned char sum
[16];
81 mdfour_update(&md4
, NULL
, 0);
82 mdfour_result(&md4
, sum
);
84 for (int i
=0; i
<16; i
++)
86 rstream
<< hex
<< setfill('0') << setw(2) << (unsigned)sum
[i
];
88 rstream
<< "_" << setw(0) << dec
<< (unsigned)md4
.totalN
;
92 void create_hash_log(const string
&type_str
, const string
&parms
, const string
&result
, const string
&hash_log_path
)
97 string
time_str(ctime (&rawtime
));
99 log_file
.open(hash_log_path
.c_str());
100 log_file
<< "[" << time_str
.substr(0,time_str
.length()-1); // erase terminated '\n'
101 log_file
<< "]" << type_str
;
102 log_file
<< ": " << parms
<< endl
;
103 log_file
<< "result:" << result
<< endl
;
108 get_base_hash (systemtap_session
& s
)
113 s
.base_hash
= new hash();
114 hash
& h
= *s
.base_hash
;
116 // Hash kernel release and arch.
117 h
.add(s
.kernel_release
);
118 h
.add(s
.kernel_build_tree
);
119 h
.add(s
.architecture
);
121 // Hash a few kernel version/build-id files too
122 // (useful for kernel developers reusing a single source tree)
123 h
.add_file(s
.kernel_build_tree
+ "/.config");
124 h
.add_file(s
.kernel_build_tree
+ "/.version");
125 h
.add_file(s
.kernel_build_tree
+ "/include/linux/compile.h");
126 h
.add_file(s
.kernel_build_tree
+ "/include/linux/version.h");
127 h
.add_file(s
.kernel_build_tree
+ "/include/linux/utsrelease.h");
129 // If the kernel is a git working directory, then add the git HEAD
130 // revision to our hash as well.
131 // XXX avoiding this for now, because it's potentially expensive and has
132 // uncertain gain. The only corner case that this may help is if a developer
133 // is switching the source tree without rebuilding the kernel...
134 ///h.add(git_revision(s.kernel_build_tree));
136 // Hash runtime path (that gets added in as "-R path").
137 h
.add(s
.runtime_path
);
139 // Hash compiler path, size, and mtime. We're just going to assume
140 // we'll be using gcc. XXX: getting kbuild to spit out out would be
142 h
.add_file(find_executable("gcc"));
144 // Hash the systemtap size and mtime. We could use VERSION/DATE,
145 // but when developing systemtap that doesn't work well (since you
146 // can compile systemtap multiple times in 1 day). Since we don't
147 // know exactly where we're getting run from, we'll use
149 h
.add_file("/proc/self/exe");
156 create_hashdir (systemtap_session
& s
, const string
& result
, string
& hashdir
)
160 // Use a N level subdir for the cache path to reduce the impact on
161 // filesystems which are slow for large directories. Let N be adjustable.
162 const char *s_n
= getenv("SYSTEMTAP_NLEVELS");
166 if (nlevels
< 1) nlevels
= 1;
167 if (nlevels
> 8) nlevels
= 8;
170 hashdir
= s
.cache_path
;
172 for (int i
= 0; i
< nlevels
; i
++)
174 hashdir
+= string("/") + result
[i
*2] + result
[i
*2 + 1];
175 if (create_dir(hashdir
.c_str()) != 0)
177 if (! s
.suppress_warnings
)
178 cerr
<< "Warning: failed to create cache directory (\""
179 << hashdir
+ "\"): " << strerror(errno
)
180 << ", disabling cache support." << endl
;
181 s
.use_cache
= s
.use_script_cache
= false;
190 find_script_hash (systemtap_session
& s
, const string
& script
)
192 hash
h(get_base_hash(s
));
195 // Hash getuid. This really shouldn't be necessary (since who you
196 // are doesn't change the generated output), but the hash gets used
197 // as the module name. If two different users try to run the same
198 // script at the same time, we need something to differentiate the
202 // Hash user-specified arguments (that change the generated module).
203 h
.add(s
.bulk_mode
); // '-b'
204 h
.add(s
.timing
); // '-t'
205 h
.add(s
.prologue_searching
); // '-P'
206 h
.add(s
.ignore_vmlinux
); // --ignore-vmlinux
207 h
.add(s
.ignore_dwarf
); // --ignore-dwarf
208 h
.add(s
.consult_symtab
); // --kelf, --kmap
209 h
.add(s
.skip_badvars
); // --skip-badvars
210 h
.add(s
.unprivileged
); // --unprivileged
211 h
.add(s
.omit_werror
); // undocumented, evil
212 if (!s
.kernel_symtab_path
.empty()) // --kmap
214 h
.add(s
.kernel_symtab_path
);
215 if (stat(s
.kernel_symtab_path
.c_str(), &st
) == 0)
217 // NB: stat of /proc/kallsyms always returns size=0, mtime=now...
218 // which is a good reason to use the default /boot/System.map-2.6.xx
224 for (unsigned i
= 0; i
< s
.macros
.size(); i
++)
227 // Add any custom kbuild flags (-B)
228 for (unsigned i
= 0; i
< s
.kbuildflags
.size(); i
++)
229 h
.add(s
.kbuildflags
[i
]);
232 for (set
<string
>::iterator it
= s
.unwindsym_modules
.begin();
233 it
!= s
.unwindsym_modules
.end();
236 // XXX: a build-id of each module might be even better
238 // Add in pass 2 script output.
241 // Get the directory path to store our cached script
242 string result
, hashdir
;
244 if (!create_hashdir(s
, result
, hashdir
))
247 // Update module name to be 'stap_{hash start}'. '{hash start}'
248 // must not be too long. This shouldn't happen, since the maximum
249 // size of a hash is 32 fixed chars + 1 (for the '_') + a max of 11.
250 s
.module_name
= "stap_" + result
;
251 if (s
.module_name
.size() >= (MODULE_NAME_LEN
- 1))
252 s
.module_name
.resize(MODULE_NAME_LEN
- 1);
254 // 'ccache' would use a hash path of something like:
255 // s.hash_path = hashdir + "/" + result.substr(nlevels);
256 // which would look like:
257 // ~/.stap_cache/A/B/CDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX
259 // We're using the following so that the module can be used straight
260 // from the cache if desired. This ends up looking like this:
261 // ~/.stap_cache/A/B/stap_ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF_XXX.ko
262 s
.hash_path
= hashdir
+ "/" + s
.module_name
+ ".ko";
264 // Update C source name with new module_name.
265 s
.translated_source
= string(s
.tmpdir
) + "/" + s
.module_name
+ ".c";
266 create_hash_log(string("script_hash"), h
.get_parms(), result
,
267 hashdir
+ "/" + s
.module_name
+ "_hash.log");
272 find_stapconf_hash (systemtap_session
& s
)
274 hash
h(get_base_hash(s
));
276 // Add any custom kbuild flags
277 for (unsigned i
= 0; i
< s
.kbuildflags
.size(); i
++)
278 h
.add(s
.kbuildflags
[i
]);
280 // Get the directory path to store our cached stapconf parameters
281 string result
, hashdir
;
283 if (!create_hashdir(s
, result
, hashdir
))
286 s
.stapconf_name
= "stapconf_" + result
+ ".h";
287 s
.stapconf_path
= hashdir
+ "/" + s
.stapconf_name
;
288 create_hash_log(string("stapconf_hash"), h
.get_parms(), result
,
289 hashdir
+ "/stapconf_" + result
+ "_hash.log");
294 find_tracequery_hash (systemtap_session
& s
, const vector
<string
>& headers
)
296 hash
h(get_base_hash(s
));
298 // Add the tracepoint headers to the computed hash
299 for (size_t i
= 0; i
< headers
.size(); ++i
)
300 h
.add_file(headers
[i
]);
302 // Add any custom kbuild flags
303 for (unsigned i
= 0; i
< s
.kbuildflags
.size(); i
++)
304 h
.add(s
.kbuildflags
[i
]);
306 // Get the directory path to store our cached module
307 string result
, hashdir
;
309 if (!create_hashdir(s
, result
, hashdir
))
312 create_hash_log(string("tracequery_hash"), h
.get_parms(), result
,
313 hashdir
+ "/tracequery_" + result
+ "_hash.log");
314 return hashdir
+ "/tracequery_" + result
+ ".ko";
319 find_typequery_hash (systemtap_session
& s
, const string
& name
)
321 hash
h(get_base_hash(s
));
323 // Add the typequery name to distinguish the hash
327 // Add any custom kbuild flags
328 for (unsigned i
= 0; i
< s
.kbuildflags
.size(); i
++)
329 h
.add(s
.kbuildflags
[i
]);
331 // Get the directory path to store our cached module
332 string result
, hashdir
;
334 if (!create_hashdir(s
, result
, hashdir
))
337 create_hash_log(string("typequery_hash"), h
.get_parms(), result
,
338 hashdir
+ "/typequery_" + result
+ "_hash.log");
339 return hashdir
+ "/typequery_" + result
340 + (name
[0] == 'k' ? ".ko" : ".so");
343 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.053601 seconds and 5 git commands to generate.