memprof 0.2.6 → 0.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/bin_api.h +12 -0
- data/ext/elf.c +52 -0
- data/ext/mach.c +46 -8
- data/ext/x86_64.c +1 -1
- data/ext/x86_64.h +83 -25
- data/memprof.gemspec +1 -1
- metadata +4 -11
data/ext/bin_api.h
CHANGED
@@ -39,6 +39,18 @@ bin_init();
|
|
39
39
|
void *
|
40
40
|
bin_find_symbol(const char *sym, size_t *size);
|
41
41
|
|
42
|
+
/*
|
43
|
+
* bin_find_symbol_name - find a symbol's name
|
44
|
+
*
|
45
|
+
* Given:
|
46
|
+
* - sym - a symbol address
|
47
|
+
*
|
48
|
+
* This function will search for the symbol sym and return its name if
|
49
|
+
* found, or NULL if the symbol could not be found.
|
50
|
+
*/
|
51
|
+
const char *
|
52
|
+
bin_find_symbol_name(void *sym);
|
53
|
+
|
42
54
|
/*
|
43
55
|
* bin_allocate_page - allocate a page suitable for trampolines
|
44
56
|
*
|
data/ext/elf.c
CHANGED
@@ -301,6 +301,58 @@ bin_find_symbol(const char *sym, size_t *size)
|
|
301
301
|
return do_bin_find_symbol(sym, size, ruby_info);
|
302
302
|
}
|
303
303
|
|
304
|
+
/*
|
305
|
+
* do_bin_find_symbol_name - internal symbol name lookup function.
|
306
|
+
*
|
307
|
+
* Given:
|
308
|
+
* - sym - the symbol address to look up
|
309
|
+
* - elf - an elf information structure
|
310
|
+
*
|
311
|
+
* This function will return the name of the symbol
|
312
|
+
* or NULL if nothing can be found.
|
313
|
+
*/
|
314
|
+
static const char *
|
315
|
+
do_bin_find_symbol_name(void *sym, struct elf_info *elf)
|
316
|
+
{
|
317
|
+
char *name = NULL;
|
318
|
+
void *ptr;
|
319
|
+
|
320
|
+
assert(sym != NULL);
|
321
|
+
assert(elf != NULL);
|
322
|
+
|
323
|
+
assert(elf->symtab_data != NULL);
|
324
|
+
assert(elf->symtab_data->d_buf != NULL);
|
325
|
+
|
326
|
+
ElfW(Sym) *esym = (ElfW(Sym)*) elf->symtab_data->d_buf;
|
327
|
+
ElfW(Sym) *lastsym = (ElfW(Sym)*) ((char*) elf->symtab_data->d_buf + elf->symtab_data->d_size);
|
328
|
+
|
329
|
+
assert(esym <= lastsym);
|
330
|
+
|
331
|
+
for (; esym < lastsym; esym++){
|
332
|
+
/* ignore weak/numeric/empty symbols */
|
333
|
+
if ((esym->st_value == 0) ||
|
334
|
+
(ELF32_ST_BIND(esym->st_info)== STB_WEAK) ||
|
335
|
+
(ELF32_ST_BIND(esym->st_info)== STB_NUM))
|
336
|
+
continue;
|
337
|
+
|
338
|
+
ptr = elf->base_addr + (void *)esym->st_value;
|
339
|
+
name = elf_strptr(elf->elf, elf->symtab_shdr.sh_link, (size_t)esym->st_name);
|
340
|
+
|
341
|
+
if (ptr == sym)
|
342
|
+
return name;
|
343
|
+
}
|
344
|
+
|
345
|
+
return NULL;
|
346
|
+
}
|
347
|
+
|
348
|
+
/*
|
349
|
+
* Do the same thing as in bin_find_symbol above, but compare addresses and return the string name.
|
350
|
+
*/
|
351
|
+
const char *
|
352
|
+
bin_find_symbol_name(void *sym) {
|
353
|
+
return do_bin_find_symbol_name(sym, ruby_info);
|
354
|
+
}
|
355
|
+
|
304
356
|
/*
|
305
357
|
* bin_update_image - update the ruby binary image in memory.
|
306
358
|
*
|
data/ext/mach.c
CHANGED
@@ -323,13 +323,6 @@ build_sorted_nlist_table(const struct mach_header_64 *hdr, uint32_t *nsyms, uint
|
|
323
323
|
|
324
324
|
void *
|
325
325
|
bin_find_symbol(const char *symbol, size_t *size) {
|
326
|
-
/* Correctly prefix the symbol with a '_' (whats a prettier way to do this?) */
|
327
|
-
size_t len = strlen(symbol);
|
328
|
-
char real_symbol[len + 2];
|
329
|
-
memcpy(real_symbol, "_", 1);
|
330
|
-
memcpy((real_symbol + 1), symbol, len);
|
331
|
-
memcpy((real_symbol + len + 1), "\0", 1);
|
332
|
-
|
333
326
|
void *ptr = NULL;
|
334
327
|
void *file = NULL;
|
335
328
|
|
@@ -354,7 +347,7 @@ bin_find_symbol(const char *symbol, size_t *size) {
|
|
354
347
|
const struct nlist_64 *nlist_entry = nlist_table[i];
|
355
348
|
const char *string = string_table + nlist_entry->n_un.n_strx;
|
356
349
|
|
357
|
-
if (strcmp(
|
350
|
+
if (string && strcmp(symbol, string+1) == 0) {
|
358
351
|
const uint64_t addr = nlist_entry->n_value;
|
359
352
|
/* Add the slide to get the *real* address in the process. */
|
360
353
|
ptr = (void*)(addr + _dyld_get_image_vmaddr_slide(index));
|
@@ -391,6 +384,51 @@ bin_find_symbol(const char *symbol, size_t *size) {
|
|
391
384
|
return ptr;
|
392
385
|
}
|
393
386
|
|
387
|
+
/*
|
388
|
+
* Do the same thing as in bin_find_symbol above, but compare addresses and return the string name.
|
389
|
+
*/
|
390
|
+
const char *
|
391
|
+
bin_find_symbol_name(void *symbol) {
|
392
|
+
const char *name = NULL;
|
393
|
+
void *ptr = NULL;
|
394
|
+
void *file = NULL;
|
395
|
+
|
396
|
+
uint32_t i, j, k;
|
397
|
+
uint32_t stroff, nsyms = 0;
|
398
|
+
int index = 0;
|
399
|
+
|
400
|
+
file = get_ruby_file_and_header_index(&index);
|
401
|
+
|
402
|
+
const struct mach_header_64 *hdr = (const struct mach_header_64*) file;
|
403
|
+
if (hdr->magic != MH_MAGIC_64)
|
404
|
+
errx(EX_SOFTWARE, "Magic for Ruby Mach-O file doesn't match");
|
405
|
+
|
406
|
+
const struct nlist_64 **nlist_table = build_sorted_nlist_table(hdr, &nsyms, &stroff);
|
407
|
+
/*
|
408
|
+
* The string names of symbols are stored separately from the symbol table.
|
409
|
+
* The symbol table entries contain a string 'index', which is an offset into this region.
|
410
|
+
*/
|
411
|
+
const char *string_table = (const char*)hdr + stroff;
|
412
|
+
|
413
|
+
for (i=0; i < nsyms; i++) {
|
414
|
+
const struct nlist_64 *nlist_entry = nlist_table[i];
|
415
|
+
const char *string = string_table + nlist_entry->n_un.n_strx;
|
416
|
+
|
417
|
+
const uint64_t addr = nlist_entry->n_value;
|
418
|
+
/* Add the slide to get the *real* address in the process. */
|
419
|
+
void *ptr = (void*)(addr + _dyld_get_image_vmaddr_slide(index));
|
420
|
+
|
421
|
+
if (ptr == symbol) {
|
422
|
+
name = string+1;
|
423
|
+
break;
|
424
|
+
}
|
425
|
+
}
|
426
|
+
|
427
|
+
free(nlist_table);
|
428
|
+
free(file);
|
429
|
+
return name;
|
430
|
+
}
|
431
|
+
|
394
432
|
/*
|
395
433
|
* I will explain bin_update_image with imaginary Ruby code:
|
396
434
|
*
|
data/ext/x86_64.c
CHANGED
@@ -168,7 +168,7 @@ arch_insert_inline_st2_tramp(void *addr, void *marker, void *trampoline, void *t
|
|
168
168
|
* This is to arrange for the new value in freelist to be in %rdi, and as such
|
169
169
|
* be the first argument to the C handler. As per the amd64 ABI.
|
170
170
|
*/
|
171
|
-
default_inline_st2_tramp.frame.rdi_source_displacement = marker - (void *)&(entry->frame.
|
171
|
+
default_inline_st2_tramp.frame.rdi_source_displacement = marker - (void *)&(entry->frame.align_rsp);
|
172
172
|
|
173
173
|
/* jmp back to the instruction after stage 1 trampoline was inserted
|
174
174
|
*
|
data/ext/x86_64.h
CHANGED
@@ -90,18 +90,40 @@ static struct tramp_st2_entry {
|
|
90
90
|
*
|
91
91
|
* This structure represents the assembly code:
|
92
92
|
*
|
93
|
-
* mov
|
94
|
-
*
|
95
|
-
*
|
96
|
-
*
|
97
|
-
*
|
98
|
-
*
|
99
|
-
*
|
100
|
-
*
|
101
|
-
*
|
102
|
-
*
|
103
|
-
*
|
104
|
-
*
|
93
|
+
* mov SOURCE_REGISTER,-0x3f90d4a7(%rip) # update freelist
|
94
|
+
*
|
95
|
+
* # save caller saved registers here
|
96
|
+
*
|
97
|
+
* push %rax
|
98
|
+
* push %rcx
|
99
|
+
* push %rdx
|
100
|
+
* push %rsi
|
101
|
+
* push %rdi
|
102
|
+
* push %r8
|
103
|
+
* push %r9
|
104
|
+
* push %r10
|
105
|
+
* push %r11
|
106
|
+
* push %rbp
|
107
|
+
* mov %rsp,%rbp
|
108
|
+
* mov -0x3f90d4bf(%rip),%rdi # move freelist into rdi as arg1
|
109
|
+
* and $0xfffffffffffffff0,%rsp # align stack pointer
|
110
|
+
* mov $0x7ffff65e74e0,%rcx # put handler function into position
|
111
|
+
* callq *%rcx # call handler
|
112
|
+
*
|
113
|
+
* # restore caller saved registers here
|
114
|
+
*
|
115
|
+
* leaveq
|
116
|
+
* pop %r11
|
117
|
+
* pop %r10
|
118
|
+
* pop %r9
|
119
|
+
* pop %r8
|
120
|
+
* pop %rdi
|
121
|
+
* pop %rsi
|
122
|
+
* pop %rdx
|
123
|
+
* pop %rcx
|
124
|
+
* pop %rax
|
125
|
+
*
|
126
|
+
* jmpq 0x433972 <gc_sweep+754> # jump back
|
105
127
|
*/
|
106
128
|
static struct inline_tramp_st2_entry {
|
107
129
|
unsigned char rex;
|
@@ -110,20 +132,42 @@ static struct inline_tramp_st2_entry {
|
|
110
132
|
uint32_t mov_displacement;
|
111
133
|
|
112
134
|
struct {
|
135
|
+
/*
|
136
|
+
* XXX xmm0-xmm7 are caller saved, too.
|
137
|
+
*/
|
138
|
+
unsigned char push_rax;
|
139
|
+
unsigned char push_rcx;
|
140
|
+
unsigned char push_rdx;
|
141
|
+
unsigned char push_rsi;
|
113
142
|
unsigned char push_rdi;
|
143
|
+
unsigned char push_r8[2];
|
144
|
+
unsigned char push_r9[2];
|
145
|
+
unsigned char push_r10[2];
|
146
|
+
unsigned char push_r11[2];
|
147
|
+
|
148
|
+
unsigned char push_rbp;
|
149
|
+
unsigned char mov_rsp_rbp[3];
|
150
|
+
|
114
151
|
unsigned char mov_rdi[3];
|
115
152
|
uint32_t rdi_source_displacement;
|
116
|
-
|
117
|
-
unsigned char push_rbp;
|
118
|
-
unsigned char save_rsp[3];
|
153
|
+
|
119
154
|
unsigned char align_rsp[4];
|
120
155
|
unsigned char mov[2];
|
121
156
|
void *addr;
|
122
157
|
unsigned char call[2];
|
158
|
+
|
123
159
|
unsigned char leave;
|
124
|
-
|
125
|
-
unsigned char
|
126
|
-
|
160
|
+
|
161
|
+
unsigned char pop_r11[2];
|
162
|
+
unsigned char pop_r10[2];
|
163
|
+
unsigned char pop_r9[2];
|
164
|
+
unsigned char pop_r8[2];
|
165
|
+
unsigned char pop_rdi;
|
166
|
+
unsigned char pop_rsi;
|
167
|
+
unsigned char pop_rdx;
|
168
|
+
unsigned char pop_rcx;
|
169
|
+
unsigned char pop_rax;
|
170
|
+
} __attribute__((__packed__)) frame;
|
127
171
|
|
128
172
|
unsigned char jmp;
|
129
173
|
uint32_t jmp_displacement;
|
@@ -134,19 +178,33 @@ static struct inline_tramp_st2_entry {
|
|
134
178
|
.mov_displacement = 0,
|
135
179
|
|
136
180
|
.frame = {
|
181
|
+
.push_rax = 0x50,
|
182
|
+
.push_rcx = 0x51,
|
183
|
+
.push_rdx = 0x52,
|
184
|
+
.push_rsi = 0x56,
|
137
185
|
.push_rdi = 0x57,
|
186
|
+
.push_r8 = {0x41, 0x50},
|
187
|
+
.push_r9 = {0x41, 0x51},
|
188
|
+
.push_r10 = {0x41, 0x52},
|
189
|
+
.push_r11 = {0x41, 0x53},
|
190
|
+
.push_rbp = 0x55,
|
191
|
+
.mov_rsp_rbp = {0x48, 0x89, 0xe5},
|
138
192
|
.mov_rdi = {0x48, 0x8b, 0x3d},
|
139
193
|
.rdi_source_displacement = 0,
|
140
|
-
.push_rbx = 0x53,
|
141
|
-
.push_rbp = 0x55,
|
142
|
-
.save_rsp = {0x48, 0x89, 0xe5},
|
143
194
|
.align_rsp = {0x48, 0x83, 0xe4, 0xf0},
|
144
|
-
.mov = {0x48,
|
195
|
+
.mov = {0x48, 0xb9},
|
145
196
|
.addr = 0,
|
146
|
-
.call = {0xff,
|
197
|
+
.call = {0xff, 0xd1},
|
147
198
|
.leave = 0xc9,
|
148
|
-
.
|
149
|
-
.
|
199
|
+
.pop_r11 = {0x41, 0x5b},
|
200
|
+
.pop_r10 = {0x41, 0x5a},
|
201
|
+
.pop_r9 = {0x41, 0x59},
|
202
|
+
.pop_r8 = {0x41, 0x58},
|
203
|
+
.pop_rdi = 0x5f,
|
204
|
+
.pop_rsi = 0x5e,
|
205
|
+
.pop_rdx = 0x5a,
|
206
|
+
.pop_rcx = 0x59,
|
207
|
+
.pop_rax = 0x58,
|
150
208
|
},
|
151
209
|
|
152
210
|
.jmp = 0xe9,
|
data/memprof.gemspec
CHANGED
metadata
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: memprof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 2
|
8
|
-
- 6
|
9
|
-
version: 0.2.6
|
4
|
+
version: 0.2.7
|
10
5
|
platform: ruby
|
11
6
|
authors:
|
12
7
|
- Joe Damato
|
@@ -66,20 +61,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
61
|
requirements:
|
67
62
|
- - ">="
|
68
63
|
- !ruby/object:Gem::Version
|
69
|
-
segments:
|
70
|
-
- 0
|
71
64
|
version: "0"
|
65
|
+
version:
|
72
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
67
|
requirements:
|
74
68
|
- - ">="
|
75
69
|
- !ruby/object:Gem::Version
|
76
|
-
segments:
|
77
|
-
- 0
|
78
70
|
version: "0"
|
71
|
+
version:
|
79
72
|
requirements: []
|
80
73
|
|
81
74
|
rubyforge_project:
|
82
|
-
rubygems_version: 1.3.
|
75
|
+
rubygems_version: 1.3.5
|
83
76
|
signing_key:
|
84
77
|
specification_version: 3
|
85
78
|
summary: Ruby Memory Profiler
|