memprof 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Rakefile +30 -0
- data/bin/memprof +158 -0
- data/ext/bin_api.h +6 -2
- data/ext/elf.c +146 -46
- data/ext/extconf.rb +39 -13
- data/ext/mach.c +3 -3
- data/ext/memprof.c +923 -95
- data/ext/tramp.c +2 -2
- data/ext/util.c +1 -0
- data/ext/util.h +34 -2
- data/lib/memprof/signal.rb +16 -0
- data/memprof.gemspec +5 -1
- data/spec/memprof_spec.rb +2 -2
- data/spec/memprof_uploader_spec.rb +117 -0
- metadata +35 -8
- data/lib/memprof/usr2.rb +0 -10
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -7,3 +7,33 @@ task :spec do
|
|
7
7
|
sh "ruby spec/memprof_spec.rb"
|
8
8
|
end
|
9
9
|
task :default => :spec
|
10
|
+
|
11
|
+
# Should be used like:
|
12
|
+
# rake --trace ci[1.8.7,shared]
|
13
|
+
|
14
|
+
task :ci, [:ruby_type, :lib_option] do |t, args|
|
15
|
+
ruby_type, lib_option = args[:ruby_type], args[:lib_option]
|
16
|
+
raise "#{ruby_type} is not a supported ruby version" unless ["1.8.6", "1.8.7", "ree"].include?(ruby_type)
|
17
|
+
raise "#{lib_option} is not a supported " unless ["shared", "static"].include?(lib_option)
|
18
|
+
|
19
|
+
lib_option = case lib_option
|
20
|
+
when "static"
|
21
|
+
"--disable-shared"
|
22
|
+
when "shared"
|
23
|
+
"--enable-shared"
|
24
|
+
end
|
25
|
+
|
26
|
+
sh "/usr/bin/env bash -c \"
|
27
|
+
source ~/.rvm/scripts/rvm &&
|
28
|
+
rvm install #{ruby_type} --reconfigure -C #{lib_option} &&
|
29
|
+
rvm #{ruby_type} --symlink memprof &&
|
30
|
+
memprof_gem install bacon\""
|
31
|
+
|
32
|
+
Dir.chdir('ext') do
|
33
|
+
sh '/usr/bin/env bash -c "make clean"' rescue nil
|
34
|
+
sh "~/.rvm/bin/memprof_ruby extconf.rb"
|
35
|
+
sh '/usr/bin/env bash -c "make"'
|
36
|
+
end
|
37
|
+
sh "~/.rvm/bin/memprof_ruby spec/memprof_spec.rb"
|
38
|
+
end
|
39
|
+
|
data/bin/memprof
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optparse'
|
5
|
+
require 'restclient'
|
6
|
+
require 'term/ansicolor'
|
7
|
+
|
8
|
+
MEMPROF_URL = "https://memprof.com/upload"
|
9
|
+
|
10
|
+
MEMPROF_BANNER = <<-EOF
|
11
|
+
Memprof Uploader
|
12
|
+
http://www.memprof.com
|
13
|
+
======================
|
14
|
+
|
15
|
+
EOF
|
16
|
+
|
17
|
+
class MemprofUploader
|
18
|
+
include Term::ANSIColor
|
19
|
+
|
20
|
+
def initialize(args=ARGV)
|
21
|
+
puts MEMPROF_BANNER
|
22
|
+
|
23
|
+
@parser = OptionParser.new do |opts|
|
24
|
+
opts.banner = "Usage:"
|
25
|
+
opts.on("-p", "--pid <pid>", Integer, "PID of the process to dump (required)") {|arg| @pid = arg }
|
26
|
+
opts.on("-n", "--name <name>", "Name for your dump (required)") {|arg| @name = arg }
|
27
|
+
opts.on("-k", "--key <key>", "Memprof.com API key (required)") {|arg| @key = arg }
|
28
|
+
opts.on("-d", "--[no-]delete", "Delete dump file after uploading (default true)") {|arg| @delete_dump = arg }
|
29
|
+
opts.on("-s", "--seconds <seconds>", "Seconds to wait for the dump (default 60)") {|arg| @secs = arg}
|
30
|
+
opts.on("-t", "--[no-]test", "Test run (don't actually upload) (default false)") {|arg| @test = arg }
|
31
|
+
opts.on("-f", "--file <path>", "Upload specific json dump (optional)") {|arg| @file = arg }
|
32
|
+
opts.on("--put-my-data-on-the-internet", "Confirm that you understand\n" +
|
33
|
+
"memprof.com will show all your \n".rjust(80) +
|
34
|
+
"internal data on the internet (required)".rjust(80)) {|arg| @confirmed = true}
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
@parser.parse!
|
39
|
+
rescue Exception => e
|
40
|
+
if e.kind_of?(SystemExit)
|
41
|
+
raise e
|
42
|
+
else
|
43
|
+
fail_with(e.message)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Make this default to true if the user didn't pass any preference.
|
48
|
+
@delete_dump = true if @delete_dump.nil?
|
49
|
+
|
50
|
+
# Make this default to 60 if the user didn't pass the number of seconds.
|
51
|
+
@secs = 60 if @secs.nil?
|
52
|
+
|
53
|
+
if @file
|
54
|
+
fail_with("File not found: #{@file}") unless File.exists?(@file)
|
55
|
+
end
|
56
|
+
|
57
|
+
if @pid.nil? and @file.nil?
|
58
|
+
fail_with("Missing PID! (-p PID)")
|
59
|
+
elsif @name.nil? || @name.empty?
|
60
|
+
fail_with("Missing name! (-n 'my application')")
|
61
|
+
elsif @key.nil? || @key.empty?
|
62
|
+
fail_with("Missing API key! (-k KEY)")
|
63
|
+
elsif !@confirmed
|
64
|
+
fail_with("\nERROR: You MUST CONFIRM that you understand ALL YOUR CODE "+
|
65
|
+
"WILL BE PUBLICLY \nAVAILABLE ON THE INTERNET by passing " +
|
66
|
+
"--put-my-data-on-the-internet", true)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def run!
|
71
|
+
dump_filename = @file ? compress_file(@file, "/tmp/#{File.basename @file}.gz") : compress_file(get_dump_filename(@pid))
|
72
|
+
|
73
|
+
begin
|
74
|
+
upload_dump(dump_filename, @name, @key)
|
75
|
+
ensure
|
76
|
+
if @delete_dump
|
77
|
+
File.delete(dump_filename)
|
78
|
+
puts "\nDeleted dump file."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
puts "Finished!"
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def compress_file(filename, output=nil)
|
88
|
+
puts "Compressing with gzip..."
|
89
|
+
output ||= "#{filename}.gz"
|
90
|
+
`gzip -c '#{filename}' > '#{output}'`
|
91
|
+
output
|
92
|
+
end
|
93
|
+
|
94
|
+
def get_dump_filename(pid)
|
95
|
+
# Get a listing of files before we signal for the new dump
|
96
|
+
# We'll compare against this later to see which is the new file.
|
97
|
+
old_files = Dir.glob("/tmp/memprof-#{pid}-*")
|
98
|
+
signal_process(pid)
|
99
|
+
puts "Waiting 5 seconds for process #{pid} to create a new dump..."
|
100
|
+
|
101
|
+
file = nil
|
102
|
+
|
103
|
+
5.times do |i|
|
104
|
+
sleep 1 unless file = (Dir.glob("/tmp/memprof-#{pid}-*") - old_files).first and break
|
105
|
+
fail_with("Timed out after waiting 5 seconds. Make sure you added require '#{File.expand_path('../../lib/memprof/signal', __FILE__)}' to your application.") if i+1 == 5
|
106
|
+
end
|
107
|
+
|
108
|
+
puts "\nFound file #{file}"
|
109
|
+
|
110
|
+
if file =~ /\.IN_PROGRESS/
|
111
|
+
file = file.sub(/\.IN_PROGRESS/, "")
|
112
|
+
puts "Dump in progress. Waiting #{@secs} seconds for it to complete..."
|
113
|
+
@secs.times do |i|
|
114
|
+
sleep 1 unless File.exist?(file) and break
|
115
|
+
fail_with("Timed out after waiting #{@secs} seconds") if i+1 == @secs
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
file
|
120
|
+
end
|
121
|
+
|
122
|
+
def upload_dump(filename, name, key)
|
123
|
+
return if @test
|
124
|
+
|
125
|
+
file = File.open(filename, "r")
|
126
|
+
|
127
|
+
puts "\nUploading to memprof.com..."
|
128
|
+
response = RestClient.post(MEMPROF_URL, :upload => file, :name => name, :key => key)
|
129
|
+
|
130
|
+
puts "Response from server:"
|
131
|
+
p response.to_s
|
132
|
+
end
|
133
|
+
|
134
|
+
def fail_with(str, yell=true)
|
135
|
+
puts @parser.to_s
|
136
|
+
puts
|
137
|
+
if yell
|
138
|
+
print red, bold, str, reset
|
139
|
+
puts
|
140
|
+
else
|
141
|
+
puts "\n" + str
|
142
|
+
end
|
143
|
+
puts
|
144
|
+
exit(1)
|
145
|
+
end
|
146
|
+
|
147
|
+
def signal_process(pid)
|
148
|
+
begin
|
149
|
+
Process.kill("URG", pid)
|
150
|
+
rescue Errno::ESRCH
|
151
|
+
fail_with("No such process #{pid}!")
|
152
|
+
end
|
153
|
+
puts "Signaled process #{pid} with SIGURG"
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
MemprofUploader.new(ARGV).run!
|
data/ext/bin_api.h
CHANGED
@@ -21,6 +21,8 @@ bin_init();
|
|
21
21
|
* Given:
|
22
22
|
* - sym - a symbol name
|
23
23
|
* - size - optional out parameter
|
24
|
+
* - search_libs - 0 to search only ruby/libruby, 1 to search other
|
25
|
+
* libraries, too.
|
24
26
|
*
|
25
27
|
* This function will search for the symbol sym and return its address if
|
26
28
|
* found, or NULL if the symbol could not be found.
|
@@ -29,7 +31,7 @@ bin_init();
|
|
29
31
|
* size of the symbol.
|
30
32
|
*/
|
31
33
|
void *
|
32
|
-
bin_find_symbol(const char *sym, size_t *size);
|
34
|
+
bin_find_symbol(const char *sym, size_t *size, int search_libs);
|
33
35
|
|
34
36
|
/*
|
35
37
|
* bin_find_symbol_name - find a symbol's name
|
@@ -85,6 +87,8 @@ bin_type_member_offset(const char *type, const char *member);
|
|
85
87
|
* Given:
|
86
88
|
* - trampee - the name of the symbol to hook
|
87
89
|
* - tramp - the stage 2 trampoline entry
|
90
|
+
* - orig_func - out parameter storing the address of the function that was
|
91
|
+
* originally being called.
|
88
92
|
*
|
89
93
|
* this function will update the binary image so that all calls to trampee will
|
90
94
|
* be routed to tramp.
|
@@ -92,5 +96,5 @@ bin_type_member_offset(const char *type, const char *member);
|
|
92
96
|
* Returns 0 on success.
|
93
97
|
*/
|
94
98
|
int
|
95
|
-
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp);
|
99
|
+
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp, void **orig_func);
|
96
100
|
#endif
|
data/ext/elf.c
CHANGED
@@ -90,6 +90,7 @@ typedef enum {
|
|
90
90
|
* entry.
|
91
91
|
*/
|
92
92
|
typedef linkmap_cb_status (*linkmap_cb)(struct link_map *, void *);
|
93
|
+
typedef void (*linkmap_lib_cb)(struct elf_info *lib, void *data);
|
93
94
|
|
94
95
|
static void open_elf(struct elf_info *info);
|
95
96
|
static int dissect_elf(struct elf_info *info, int find_debug);
|
@@ -140,27 +141,36 @@ get_got_addr(struct plt_entry *plt)
|
|
140
141
|
/*
|
141
142
|
* overwrite_got - given the address of a PLT entry, overwrite the address
|
142
143
|
* in the GOT that the PLT entry uses with the address in tramp.
|
144
|
+
*
|
145
|
+
* returns the original function address
|
143
146
|
*/
|
144
|
-
static void
|
147
|
+
static void *
|
145
148
|
overwrite_got(void *plt, const void *tramp)
|
146
149
|
{
|
147
150
|
assert(plt != NULL);
|
148
151
|
assert(tramp != NULL);
|
152
|
+
void *ret = NULL;
|
153
|
+
|
154
|
+
memcpy(&ret, get_got_addr(plt), sizeof(ret));
|
149
155
|
memcpy(get_got_addr(plt), &tramp, sizeof(void *));
|
150
|
-
return;
|
156
|
+
return ret;
|
151
157
|
}
|
152
158
|
|
153
159
|
struct plt_hook_data {
|
154
160
|
const char *sym;
|
155
|
-
|
161
|
+
void *addr;
|
162
|
+
};
|
163
|
+
|
164
|
+
struct dso_iter_data {
|
165
|
+
linkmap_lib_cb cb;
|
166
|
+
void *passthru;
|
156
167
|
};
|
157
168
|
|
158
169
|
static linkmap_cb_status
|
159
|
-
|
170
|
+
for_each_dso_cb(struct link_map *map, void *data)
|
160
171
|
{
|
161
|
-
struct
|
172
|
+
struct dso_iter_data *iter_data = data;
|
162
173
|
struct elf_info curr_lib;
|
163
|
-
void *trampee_addr = NULL;
|
164
174
|
|
165
175
|
/* skip a few things we don't care about */
|
166
176
|
if (strstr(map->l_name, "linux-vdso")) {
|
@@ -203,10 +213,7 @@ hook_func_cb(struct link_map *map, void *data)
|
|
203
213
|
dbg_printf("dissected the elf file: %s, base: %lx\n",
|
204
214
|
curr_lib.filename, (unsigned long)curr_lib.base_addr);
|
205
215
|
|
206
|
-
|
207
|
-
dbg_printf("found: %s @ %p\n", hook_data->sym, trampee_addr);
|
208
|
-
overwrite_got(trampee_addr, hook_data->tramp);
|
209
|
-
}
|
216
|
+
iter_data->cb(&curr_lib, iter_data->passthru);
|
210
217
|
|
211
218
|
elf_end(curr_lib.elf);
|
212
219
|
close(curr_lib.fd);
|
@@ -214,12 +221,26 @@ hook_func_cb(struct link_map *map, void *data)
|
|
214
221
|
}
|
215
222
|
|
216
223
|
static void
|
217
|
-
|
224
|
+
for_each_dso(linkmap_lib_cb cb, void *passthru)
|
218
225
|
{
|
219
|
-
struct
|
220
|
-
data.
|
221
|
-
data.
|
222
|
-
walk_linkmap(
|
226
|
+
struct dso_iter_data data;
|
227
|
+
data.cb = cb;
|
228
|
+
data.passthru = passthru;
|
229
|
+
walk_linkmap(for_each_dso_cb, &data);
|
230
|
+
}
|
231
|
+
|
232
|
+
static void
|
233
|
+
hook_required_objects(struct elf_info *info, void *data)
|
234
|
+
{
|
235
|
+
assert(info != NULL);
|
236
|
+
struct plt_hook_data *hook_data = data;
|
237
|
+
void *trampee_addr = NULL;
|
238
|
+
|
239
|
+
if ((trampee_addr = find_plt_addr(hook_data->sym, info)) != NULL) {
|
240
|
+
dbg_printf("found: %s @ %p\n", hook_data->sym, trampee_addr);
|
241
|
+
overwrite_got(trampee_addr, hook_data->addr);
|
242
|
+
}
|
243
|
+
|
223
244
|
return;
|
224
245
|
}
|
225
246
|
|
@@ -320,6 +341,8 @@ find_plt_addr(const char *symname, struct elf_info *info)
|
|
320
341
|
info = ruby_info;
|
321
342
|
}
|
322
343
|
|
344
|
+
assert(info != NULL);
|
345
|
+
|
323
346
|
/* Search through each of the .rela.plt entries */
|
324
347
|
for (i = 0; i < info->relplt_count; i++) {
|
325
348
|
GElf_Rela rela;
|
@@ -365,38 +388,78 @@ find_plt_addr(const char *symname, struct elf_info *info)
|
|
365
388
|
static void *
|
366
389
|
do_bin_find_symbol(const char *sym, size_t *size, struct elf_info *elf)
|
367
390
|
{
|
368
|
-
char *name = NULL;
|
391
|
+
const char *name = NULL;
|
369
392
|
|
370
393
|
assert(sym != NULL);
|
371
394
|
assert(elf != NULL);
|
372
395
|
|
373
|
-
|
374
|
-
|
396
|
+
ElfW(Sym) *esym, *lastsym = NULL;
|
397
|
+
if (elf->symtab_data && elf->symtab_data->d_buf) {
|
398
|
+
dbg_printf("checking symtab....\n");
|
399
|
+
esym = (ElfW(Sym)*) elf->symtab_data->d_buf;
|
400
|
+
lastsym = (ElfW(Sym)*) ((char*) elf->symtab_data->d_buf + elf->symtab_data->d_size);
|
375
401
|
|
376
|
-
|
377
|
-
ElfW(Sym) *lastsym = (ElfW(Sym)*) ((char*) elf->symtab_data->d_buf + elf->symtab_data->d_size);
|
402
|
+
assert(esym <= lastsym);
|
378
403
|
|
379
|
-
|
404
|
+
for (; esym < lastsym; esym++){
|
405
|
+
/* ignore numeric/empty symbols */
|
406
|
+
if ((esym->st_value == 0) ||
|
407
|
+
(ELF32_ST_BIND(esym->st_info)== STB_NUM))
|
408
|
+
continue;
|
380
409
|
|
381
|
-
|
382
|
-
/* ignore weak/numeric/empty symbols */
|
383
|
-
if ((esym->st_value == 0) ||
|
384
|
-
(ELF32_ST_BIND(esym->st_info)== STB_WEAK) ||
|
385
|
-
(ELF32_ST_BIND(esym->st_info)== STB_NUM))
|
386
|
-
continue;
|
410
|
+
name = elf_strptr(elf->elf, elf->symtab_shdr.sh_link, (size_t)esym->st_name);
|
387
411
|
|
388
|
-
|
412
|
+
if (name && strcmp(name, sym) == 0) {
|
413
|
+
if (size) {
|
414
|
+
*size = esym->st_size;
|
415
|
+
}
|
416
|
+
dbg_printf("Found symbol: %s in symtab\n", sym);
|
417
|
+
return elf->base_addr + (void *)esym->st_value;
|
418
|
+
}
|
419
|
+
}
|
420
|
+
}
|
421
|
+
|
422
|
+
if (elf->dynsym && elf->dynsym->d_buf) {
|
423
|
+
dbg_printf("checking dynsymtab....\n");
|
424
|
+
esym = (ElfW(Sym) *) elf->dynsym->d_buf;
|
425
|
+
lastsym = (ElfW(Sym) *) ((char *) elf->dynsym->d_buf + elf->dynsym->d_size);
|
426
|
+
|
427
|
+
for (; esym < lastsym; esym++){
|
428
|
+
/* ignore numeric/empty symbols */
|
429
|
+
if ((esym->st_value == 0) ||
|
430
|
+
(ELF32_ST_BIND(esym->st_info)== STB_NUM))
|
431
|
+
continue;
|
389
432
|
|
390
|
-
|
391
|
-
|
392
|
-
|
433
|
+
name = elf->dynstr + esym->st_name;
|
434
|
+
|
435
|
+
if (name && strcmp(name, sym) == 0) {
|
436
|
+
if (size) {
|
437
|
+
*size = esym->st_size;
|
438
|
+
}
|
439
|
+
dbg_printf("Found symbol: %s in dynsym\n", sym);
|
440
|
+
return elf->base_addr + (void *)esym->st_value;
|
393
441
|
}
|
394
|
-
return elf->base_addr + (void *)esym->st_value;
|
395
442
|
}
|
396
443
|
}
|
444
|
+
|
445
|
+
dbg_printf("Couldn't find symbol: %s in dynsym\n", sym);
|
397
446
|
return NULL;
|
398
447
|
}
|
399
448
|
|
449
|
+
static void
|
450
|
+
find_symbol_cb(struct elf_info *info, void *data)
|
451
|
+
{
|
452
|
+
assert(info != NULL);
|
453
|
+
void *trampee_addr = NULL;
|
454
|
+
struct plt_hook_data *hook_data = data;
|
455
|
+
void *ret = do_bin_find_symbol(hook_data->sym, NULL, info);
|
456
|
+
if (ret) {
|
457
|
+
hook_data->addr = ret;
|
458
|
+
dbg_printf("found %s @ %p, fn addr: %p\n", hook_data->sym, trampee_addr,
|
459
|
+
hook_data->addr);
|
460
|
+
}
|
461
|
+
}
|
462
|
+
|
400
463
|
/*
|
401
464
|
* bin_find_symbol - find the address of a given symbol and set its size if
|
402
465
|
* desired.
|
@@ -404,9 +467,20 @@ do_bin_find_symbol(const char *sym, size_t *size, struct elf_info *elf)
|
|
404
467
|
* This function is just a wrapper for the internal symbol lookup function.
|
405
468
|
*/
|
406
469
|
void *
|
407
|
-
bin_find_symbol(const char *sym, size_t *size)
|
470
|
+
bin_find_symbol(const char *sym, size_t *size, int search_libs)
|
408
471
|
{
|
409
|
-
|
472
|
+
void *ret = do_bin_find_symbol(sym, size, ruby_info);
|
473
|
+
|
474
|
+
if (!ret && search_libs) {
|
475
|
+
dbg_printf("Didn't find symbol: %s in ruby, searching other libs\n", sym);
|
476
|
+
struct plt_hook_data hd;
|
477
|
+
hd.sym = sym;
|
478
|
+
hd.addr = NULL;
|
479
|
+
for_each_dso(find_symbol_cb, &hd);
|
480
|
+
ret = hd.addr;
|
481
|
+
}
|
482
|
+
|
483
|
+
return ret;
|
410
484
|
}
|
411
485
|
|
412
486
|
/*
|
@@ -467,6 +541,8 @@ bin_find_symbol_name(void *sym) {
|
|
467
541
|
* Given -
|
468
542
|
* trampee - the name of the symbol to hook
|
469
543
|
* tramp - the stage 2 trampoline entry
|
544
|
+
* orig_func - out parameter storing the address of the function that was
|
545
|
+
* originally called.
|
470
546
|
*
|
471
547
|
* This function will update the ruby binary image so that all calls to trampee
|
472
548
|
* will be routed to tramp.
|
@@ -474,7 +550,7 @@ bin_find_symbol_name(void *sym) {
|
|
474
550
|
* Returns 0 on success
|
475
551
|
*/
|
476
552
|
int
|
477
|
-
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp)
|
553
|
+
bin_update_image(const char *trampee, struct tramp_st2_entry *tramp, void **orig_func)
|
478
554
|
{
|
479
555
|
void *trampee_addr = NULL;
|
480
556
|
|
@@ -482,32 +558,56 @@ bin_update_image(const char *trampee, struct tramp_st2_entry *tramp)
|
|
482
558
|
assert(tramp != NULL);
|
483
559
|
assert(tramp->addr != NULL);
|
484
560
|
|
485
|
-
if
|
561
|
+
/* first check if the symbol is in the PLT */
|
562
|
+
trampee_addr = find_plt_addr(trampee, NULL);
|
563
|
+
|
564
|
+
/* it isn't in the PLT, try to find it in the binary itself */
|
565
|
+
if (!trampee_addr) {
|
566
|
+
dbg_printf("Couldn't find %s in the PLT...\n", trampee);
|
486
567
|
unsigned char *byte = ruby_info->text_segment;
|
487
|
-
trampee_addr = bin_find_symbol(trampee, NULL);
|
568
|
+
trampee_addr = bin_find_symbol(trampee, NULL, 0);
|
488
569
|
size_t count = 0;
|
489
570
|
int num = 0;
|
490
571
|
|
491
572
|
assert(byte != NULL);
|
492
|
-
|
573
|
+
|
574
|
+
if (!trampee_addr) {
|
575
|
+
dbg_printf("WARNING: Couldn't find: %s anywhere, so not tramping!\n", trampee);
|
576
|
+
return 0;
|
577
|
+
}
|
578
|
+
|
579
|
+
if (orig_func) {
|
580
|
+
*orig_func = trampee_addr;
|
581
|
+
}
|
493
582
|
|
494
583
|
for(; count < ruby_info->text_segment_len; byte++, count++) {
|
495
584
|
if (arch_insert_st1_tramp(byte, trampee_addr, tramp) == 0) {
|
496
585
|
num++;
|
497
586
|
}
|
498
587
|
}
|
588
|
+
dbg_printf("Inserted %d tramps for: %s\n", num, trampee);
|
499
589
|
} else {
|
500
|
-
|
501
|
-
|
502
|
-
overwrite_got(trampee_addr, tramp->addr);
|
503
|
-
}
|
590
|
+
void *ret = NULL;
|
591
|
+
dbg_printf("Found %s in the PLT, inserting tramp...\n", trampee);
|
592
|
+
ret = overwrite_got(trampee_addr, tramp->addr);
|
504
593
|
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
594
|
+
assert(ret != NULL);
|
595
|
+
|
596
|
+
if (orig_func) {
|
597
|
+
*orig_func = ret;
|
598
|
+
dbg_printf("setting orig function: %p\n", *orig_func);
|
599
|
+
}
|
509
600
|
}
|
510
601
|
|
602
|
+
dbg_printf("Trying to hook %s in other libraries...\n", trampee);
|
603
|
+
|
604
|
+
struct plt_hook_data data;
|
605
|
+
data.addr = tramp->addr;
|
606
|
+
data.sym = trampee;
|
607
|
+
for_each_dso(hook_required_objects, &data);
|
608
|
+
|
609
|
+
dbg_printf("Done searching other libraries for %s\n", trampee);
|
610
|
+
|
511
611
|
return 0;
|
512
612
|
}
|
513
613
|
|