memprof 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|