memprof 0.2.6 → 0.2.7

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.
@@ -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