forked from dtrace4linux/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathload.pl
More file actions
executable file
·472 lines (426 loc) · 14.2 KB
/
load.pl
File metadata and controls
executable file
·472 lines (426 loc) · 14.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
#! /usr/bin/perl
# $Header: Last edited: 29-Oct-2011 1.3 $
# 20090415 PDF Fix for when we are using the optional symbols (AS4)
# 20090416 PDF Add /boot/System.map support
# 20090416 PDF Add -unhandled switch support.
# 20090513 PDF Add copy of /etc/dtrace.conf to /dev/dtrace.
# 20090605 PDF Add -opcodes support for fbt provider.
# 20090718 PDF Add System.map26 support for Arch linux.
# 20111014 PDF Read /proc/kallsyms as root to avoid permission issue.
# 20111028 PDF Add -panic switch so I can maybe figure out why we are dying.
# 20120711 PDF Make /dev/fasttrap world read/writable.
# 20120822 PDF Remove some unneeded symbols (arch linux fix)
# 20141204 PDF Add -n support.
# Simple script to load the driver and get it ready.
use strict;
use warnings;
use File::Basename;
use FileHandle;
use Getopt::Long;
use IO::File;
use POSIX;
use Cwd;
my $SUDO = "setuid root";
#######################################################################
# Command line switches. #
#######################################################################
my %opts = (
here => 0,
mem_alloc => 0,
opcodes => 0,
opcodes2 => 0,
panic => 0,
printk => 0,
unhandled => 0,
v => 0,
);
sub main
{
Getopt::Long::Configure('no_ignore_case');
usage() unless GetOptions(\%opts,
'fast',
'help',
'here',
'mem_alloc',
'opcodes',
'opcodes2',
'n',
'panic',
'printk',
'unhandled',
'unload',
'v+',
);
usage() if ($opts{help});
if (! -f "$ENV{HOME}/bin/setuid" ) {
$SUDO = "sudo";
if (! -f "/usr/bin/sudo" && ! -f "/usr/sbin/sudo") {
$SUDO = "";
}
}
if (getuid() == 0) {
$SUDO = "";
}
my $tstart = time();
print time_string() . "Syncing...\n";
spawn("sync ; sync");
###############################################
# Get some kernel variables. #
###############################################
my $uname_m = `uname -m`;
chomp($uname_m);
my $kernel = `uname -r`;
chomp($kernel);
my $dtrace = "build/dtrace";
if (! -f $dtrace) {
###############################################
# Find dtrace - we may be in the #
# build/driver dir or some other place. #
###############################################
my $dtrace_dir = Cwd::cwd();
while ($dtrace_dir ne '/') {
last if -f "$dtrace_dir/dtrace";
$dtrace_dir = dirname($dtrace_dir);
}
$dtrace = "$dtrace_dir/dtrace";
die "Cannot locate dtrace command" if ! -f $dtrace;
}
###############################################
# Safely remove the old driver. #
###############################################
if ( -e "/dev/dtrace" ) {
my $rmmod;
foreach my $p ("/sbin", "/usr/sbin", "/usr/bin") {
my $p1 = "$p/rmmod";
$rmmod = $p1 if -x $p1;
}
if (!$rmmod) {
print "ERROR: Strange..cannot locate 'rmmod'\n";
exit(0);
}
spawn("$SUDO $rmmod dtracedrv");
spawn("sync ; sync");
exit(0) if $opts{unload};
}
###############################################
# We want get_proc_addr() to run as soon #
# as possible, so bootstrap the symbol #
# finder. #
###############################################
my $kallsyms_lookup_name = `$SUDO grep -w kallsyms_lookup_name /proc/kallsyms`;
chomp($kallsyms_lookup_name);
$kallsyms_lookup_name =~ s/ .*$//;
#####################################################################
# Here goes...we could crash the kernel... We sleep for a bit at
# present since we need the /dev entries to appear. Chmod 666 so
# we can avoid being root all the time whilst we debug.
#####################################################################
my $dtracedrv = "build-$kernel/driver/dtracedrv.ko";
print time_string() . "Loading: $dtracedrv\n";
my $opc_len = $opts{opcodes};
$opc_len = 2 if $opts{opcodes2};
my $insmod = "/sbin/insmod";
$insmod = "/usr/bin/insmod" if ! -x $insmod;
my $ret = spawn("$SUDO $insmod $dtracedrv dtrace_here=$opts{here}" .
" fbt_name_opcodes=$opc_len" .
" dtrace_unhandled=$opts{unhandled}" .
" dtrace_mem_alloc=$opts{mem_alloc}" .
" dtrace_printk=$opts{printk}" .
" grab_panic=$opts{panic}" .
" arg_kallsyms_lookup_name=0x$kallsyms_lookup_name"
);
if (! -d "/proc/dtrace") {
print "/proc/dtrace does not exist. Maybe the driver didnt load properly.\n";
exit(1);
}
if ($ret) {
my $log = -f "/var/log/messages" ? "/var/log/messages" :
-f "/var/log/kern.log" ? "/var/log/kern.log" : "/var/log/kernel.log";
print "\n";
print "An error was detected loading the driver. Refer to\n";
print "$log or 'dmesg' to see what the issue\n";
print "might be. For your convenience, here is the last few\n";
print "lines from $log:\n";
print "\n";
print "===== tail -10 $log\n";
system("$SUDO tail -10 $log");
exit(1);
}
my $sectop = "/sys/module/dtracedrv/sections/";
if ($opts{v} > 1 && -e $sectop . ".text") {
# print KGDB module load command
print "# KGDB:\n";
open(IN, $sectop . ".text");
my $line = <IN>; chomp($line);
my $cmd = "add-symbol-file dtracedrv.ko " . $line;
foreach my $s (".bss", ".eh_frame", ".data", ".rodata",
".init.text", ".exit.text") {
my $ss = $sectop . $s;
if (-e $ss && open(IN, $ss)) {
$line = <IN>; chomp($line);
$cmd .= " -s $s " . $line;
}
}
print $cmd, "\n";
}
sleep(1);
mkdev("/dev/dtrace");
mkdev("/dev/dtrace_helper");
mkdev("/dev/fasttrap");
mkdev("/dev/fbt");
###############################################
# Read symbols in /proc/kallsyms into a #
# hash. Oh dear. Recent kernels make the #
# entries in /proc/kallsyms not readable #
# if we are not root (symaddr come out as #
# zero). #
###############################################
my $fh = new FileHandle("$SUDO cat /proc/kallsyms |");
die "Cannot proceed - /proc/kallsyms - $!" if !$fh;
my %syms;
while (<$fh>) {
chomp;
my $s = (split(" ", $_))[2];
$syms{$s} = $_;
}
###############################################
# We need to know if we are a 32-bit cpu #
# or not. #
###############################################
###############################################
# Just in case - read the system map. We #
# try System.map26 for 'arch' linux, since #
# it uses a different naming convention. #
###############################################
my $fname = "/boot/System.map-$kernel";
$fname = "/boot/System.map26" if ! -f $fname;
$fh = new FileHandle($fname);
if ($fh) {
while (<$fh>) {
chomp;
###############################################
# Be careful in case /boot/System file #
# doesnt agree with /proc/kallsyms; only #
# on my hacked system. #
###############################################
my $s = (split(" ", $_))[2];
$syms{$s} = $_ if !defined($syms{$s});
}
}
###############################################
# Need to 'export' GPL symbols to the #
# driver so we can call these functions. #
# Until this is done, the driver is a #
# little unsafe(!) Items below labelled as #
# 'optional' are allowed to be missing - #
# we only ever wanted them for some #
# initial debugging, and dont need them #
# any more. #
# #
# Colon separated entries let us fallback #
# to an alternate mechanism to find what #
# we are after (see fbt_linux.c) #
###############################################
print time_string() . "Preparing symbols...\n";
my $err = 0;
# Symbols we used to need, but no longer:
# get_symbol_offset
foreach my $s (qw/
access_process_vm
kallsyms_addresses:optional
kallsyms_lookup_name
modules:print_modules
sys_call_table:optional
ia32_sys_call_table:amd64
syscall_call:optional
xtime:optional
__module_text_address
add_timer_on
old_rsp:optional
/) {
my $done = 0;
my $amd64 = 0;
my $real_name;
foreach my $rawsym (split(":", $s)) {
###############################################
# Handle case of ia32_sys_call_table which #
# is only there on a 64-bit kernel. #
###############################################
if ($rawsym eq 'amd64') {
$amd64 = 1;
next;
}
###############################################
# If symbol is optional, we dont care if #
# its not there. #
###############################################
if ($rawsym eq 'optional') {
$done = 1;
last;
}
next if !defined($syms{$rawsym});
$real_name = $rawsym if !$real_name;
my $addr = $syms{$rawsym};
$addr = join(" ", (split(" ", $syms{$rawsym}))[0..1]) . " $real_name";
if ($opts{n}) {
print "$addr\n";
$done = 1;
last;
}
my $fh = new FileHandle(">/dev/fbt");
if (!$fh) {
print "Cannot open /dev/fbt -- $!\n";
$err++;
last;
}
if ($opts{v}) {
print STDERR "echo \"$addr\" > /dev/fbt\n";
}
print $fh $addr . "\n" if $fh;
$done = 1;
last;
}
###############################################
# Handle the error conditions. We must #
# stop the driver from being usable due to #
# null-ptr derefs for symbols we must have #
# and expect to have. #
###############################################
next if $done;
###############################################
# Some symbols are cpu specific. #
###############################################
if ($amd64) { # && $uname_m =~ /64/) {
next;
}
print "ERROR: This kernel is missing: '$s'\n";
$err++;
}
if ( "$err" != 0 ) {
print <<EOF;
======================================================
If your kernel is missing one or more symbols, there may be
many reasons, such as kernel not compiled with /proc/kallsyms
support (check that exists, and see if there lots of entries).
A typical kernel will have upwards of 20,000+ entries.
If /proc/kallsyms does not exist, you will not get anywhere,
unless this load module is modified to read the uncompressed
vmlinux file (feel free to report this including the kernel/distro
information).
Run tools/bug.sh to get some information to forward to the
driver maintainer(s).
EOF
print "Please do not run dtrace - your kernel is not supported.\n";
exit(1);
}
###############################################
# Tell driver we have done the init. #
###############################################
print "echo \"1 T END_SYMS\" >/dev/fbt\n" if $opts{v} || $opts{n};
if (!$opts{n}) {
$fh = new FileHandle(">/dev/fbt");
print $fh "1 T END_SYMS\n"; # sentinel
}
exit(0) if $opts{n};
###############################################
# Keep a copy of probes to avoid polluting #
# /var/log/messages as we debug the #
# driver.. #
###############################################
if (!$opts{fast}) {
print time_string() . "Probes available: ";
my $pname = "/tmp/probes";
spawn("$SUDO rm -f /tmp/probes");
# my $pname = strftime("/tmp/probes-%Y%m%d-%H:%M", localtime);
# if ( -f "/tmp/probes.current" && ! -f $pname ) {
# if (!rename("/tmp/probes.current", "/tmp/probes.prev")) {
# print "rename error /tmp/probes.current -- $!\n";
# }
# }
spawn("$SUDO $dtrace -l | tee $pname | wc -l ");
# unlink("/tmp/probes.current");
# if (!symlink($pname, "/tmp/probes.current")) {
# print "symlink($pname, /tmp/probes.current) error -- $!\n";
# }
}
###############################################
# Load the security policy into the #
# kernel. #
###############################################
if ( -f "/etc/dtrace.conf") {
system("$SUDO sh -c \"cat /etc/dtrace.conf >/dev/dtrace\"");
}
print time_string() . "Time: ", time() - $tstart, "s\n";
###############################################
# Defer setting up dtrace_ctl til the #
# symtabs are loaded. #
###############################################
mkdev("/dev/dtrace_ctl");
###############################################
# For my personal benefit - make sure we #
# have an upto date symtab when using the #
# vmware/gdb combination. #
###############################################
if (-f ".copy-kallsyms") {
system("root cat /proc/kallsyms >/tmp/k");
system("scp /tmp/k dixxy:/tmp");
}
}
#####################################################################
# If the /dev entries are not there then maybe we are on an old
# kernel, or distro (my old non-RAMfs Knoppix distro for
# instance).
#####################################################################
sub mkdev
{ my $dev = shift;
my $name = basename($dev);
if ( ! -e "/dev/$name" && -e "/sys/class/misc/$name/dev" ) {
my $fh = new FileHandle("/sys/class/misc/$name/dev");
my $dev = <$fh>;
chomp($dev);
$dev =~ s/:/ /;
spawn("$SUDO mknod /dev/$name c $dev");
}
spawn("$SUDO chmod 666 /dev/$name");
}
sub spawn
{ my $cmd = shift;
print time_string() . $cmd, "\n" if $opts{v};
return 0 if $opts{n};
return system($cmd);
}
sub time_string
{
return strftime("%H:%M:%S ", localtime);
}
#######################################################################
# Print out command line usage. #
#######################################################################
sub usage
{
print <<EOF;
load.pl: load dtrace driver and prime the links to the kernel.
Usage: load.pl [-v] [-here] [-fast] [-mem_alloc]
Description:
Loads the dtrace driver into the kernel, prime the symbol tables,
and load the /etc/dtrace.conf policy file.
Switches:
-v Be more verbose about loading process (repeat for more).
-fast Dont do 'dtrace -l' after load to avoid kernel messages.
-here Enable tracing to /var/log/messages.
-mem_alloc Trace memory allocs (kmem_alloc/kmem_zalloc/kmem_free).
-n Dont update driver - just print out values.
-opcodes Make probes named after x86 instruction opcodes to help
debugging.
-opcodes2 Make probes named after first two bytes of opcode.
-panic Intercept the panics which can occur. Might be helpful
for dtrace developer to salvage some autopsy info.
-printk Use printk to print to console instead of /proc/dtrace/trace
-unhandled Log FBT functions we couldnt handle because of unsupported/
disassembly errors.
-unload Unload the dtrace driver.
EOF
exit(1);
}
main();
0;