memprof 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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(real_symbol, string) == 0) {
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
  *
@@ -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.push_rbx);
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
  *
@@ -90,18 +90,40 @@ static struct tramp_st2_entry {
90
90
  *
91
91
  * This structure represents the assembly code:
92
92
  *
93
- * mov SOURCE_REGISTER, freelist # update the freelist
94
- * push %rdi # save %rdi
95
- * mov freelist, %rdi # move first entry of freelist into %rdi
96
- * push %rbp # save previous %rbp
97
- * mov %rsp, %rbp # update %rbp to be current stack pointer
98
- * andl 0xFFFFFFFFFFFFFFF0, %rsp # align stack pointer as per ABI
99
- * mov ADDR, %rbx # load handler address into %rbx
100
- * callq *%rbx # call handler
101
- * leave # reset stack pointer, restore %rbp
102
- * pop %rbx # restore %rbx
103
- * pop %rdi # restore %rdi
104
- * jmp NEXT_INSN # jmp to instruction after stage 1 tramp
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
- unsigned char push_rbx;
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
- unsigned char rbx_restore;
125
- unsigned char rdi_restore;
126
- } __attribute__((__packed__)) frame;
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, 0xbb},
195
+ .mov = {0x48, 0xb9},
145
196
  .addr = 0,
146
- .call = {0xff, 0xd3},
197
+ .call = {0xff, 0xd1},
147
198
  .leave = 0xc9,
148
- .rbx_restore = 0x5b,
149
- .rdi_restore = 0x5f,
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,
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'memprof'
3
- s.version = '0.2.6'
3
+ s.version = '0.2.7'
4
4
  s.date = '2010-03-13'
5
5
  s.summary = 'Ruby Memory Profiler'
6
6
  s.description = "Ruby memory profiler similar to bleak_house, but without patches to the Ruby VM"
metadata CHANGED
@@ -1,12 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: memprof
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
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.6
75
+ rubygems_version: 1.3.5
83
76
  signing_key:
84
77
  specification_version: 3
85
78
  summary: Ruby Memory Profiler