memprof 0.1.3 → 0.2.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/README CHANGED
@@ -42,9 +42,12 @@ Currently supporting:
42
42
 
43
43
  Linux:
44
44
  x86_64 builds of Ruby Enterprise Edition 1.8.6/1.8.7
45
- x86_64 builds of MRI Ruby if built with --disable-shared
45
+ x86_64 builds of MRI Ruby (enabled-shared and disable-shared)
46
46
 
47
- Experimental support:
47
+ Experimental (somewhat broken) support:
48
+
49
+ Linux:
50
+ i386/i686 support.
48
51
 
49
52
  Snow Leopard:
50
53
  x86_64 builds of MRI (both enable-shared and disable-shared)
@@ -56,9 +59,6 @@ Coming soon:
56
59
 
57
60
  Linux:
58
61
  Tracking object allocationns in C extensions.
59
- x86_64 builds of MRI Ruby with --enable-shared
60
-
61
- i386/i686 support for all the above.
62
62
 
63
63
  CREDITS
64
64
  =======
@@ -0,0 +1,30 @@
1
+ #if !defined (_ARCH_H_)
2
+ #define _ARCH_H_
3
+
4
+ #if defined(_ARCH_i386_) || defined(_ARCH_i686_)
5
+ #include "i386.h"
6
+ #elif defined(_ARCH_x86_64_)
7
+ #include "x86_64.h"
8
+ #else
9
+ #error "Unsupported architecture! Cannot continue compilation."
10
+ #endif
11
+
12
+ /*
13
+ * "normal" trampoline
14
+ */
15
+ void *
16
+ arch_get_st2_tramp(size_t *size);
17
+
18
+ void
19
+ arch_insert_st1_tramp(void *start, void *trampee, void *tramp);
20
+
21
+ /*
22
+ * inline trampoline
23
+ */
24
+ void *
25
+ arch_get_inline_st2_tramp(size_t *size);
26
+
27
+ int
28
+ arch_insert_inline_st2_tramp(void *addr, void *marker, void *trampoline, void *table_entry);
29
+
30
+ #endif
@@ -3,67 +3,20 @@
3
3
  #include <stddef.h>
4
4
  #include <stdint.h>
5
5
 
6
- /* generic file format stuff */
7
- extern void *text_segment;
8
- extern unsigned long text_segment_len;
6
+ /* XXX get rid of this */
9
7
  extern size_t pagesize;
10
8
 
11
9
  /*
12
10
  * trampoline specific stuff
13
11
  */
14
- extern struct tramp_tbl_entry *tramp_table;
12
+ extern struct tramp_st2_entry *tramp_table;
15
13
  extern size_t tramp_size;
16
14
 
17
15
  /*
18
16
  * inline trampoline specific stuff
19
17
  */
18
+ extern struct inline_tramp_st2_entry *inline_tramp_table;
20
19
  extern size_t inline_tramp_size;
21
- extern struct inline_tramp_tbl_entry *inline_tramp_table;
22
-
23
- /* trampoline types */
24
- struct tramp_inline {
25
- unsigned char jmp[1];
26
- uint32_t displacement;
27
- unsigned char pad[2];
28
- } __attribute__((__packed__));
29
-
30
- struct tramp_tbl_entry {
31
- unsigned char rbx_save[1];
32
- unsigned char mov[2];
33
- void *addr;
34
- unsigned char callq[2];
35
- unsigned char rbx_restore[1];
36
- unsigned char ret[1];
37
- } __attribute__((__packed__));
38
-
39
- struct inline_tramp_tbl_entry {
40
- unsigned char rex[1];
41
- unsigned char mov[1];
42
- unsigned char src_reg[1];
43
- uint32_t mov_displacement;
44
-
45
- struct {
46
- unsigned char push_rdi[1];
47
- unsigned char mov_rdi[3];
48
- uint32_t rdi_source_displacement;
49
- unsigned char push_rbx[1];
50
- unsigned char push_rbp[1];
51
- unsigned char save_rsp[3];
52
- unsigned char align_rsp[4];
53
- unsigned char mov[2];
54
- void *addr;
55
- unsigned char callq[2];
56
- unsigned char leave[1];
57
- unsigned char rbx_restore[1];
58
- unsigned char rdi_restore[1];
59
- } __attribute__((__packed__)) frame;
60
-
61
- unsigned char jmp[1];
62
- uint32_t jmp_displacement;
63
- } __attribute__((__packed__));
64
-
65
- void
66
- update_callqs(int entry, void *trampee_addr);
67
20
 
68
21
  /*
69
22
  * EXPORTED API.
@@ -74,10 +27,18 @@ bin_init();
74
27
  void *
75
28
  bin_find_symbol(char *sym, size_t *size);
76
29
 
77
- void
78
- bin_update_image(int entry, void *trampee_addr);
30
+ void *
31
+ bin_find_got_addr(char *sym, void *cookie);
79
32
 
80
33
  void *
81
34
  bin_allocate_page();
82
35
 
36
+ int
37
+ bin_type_size(char *type);
38
+
39
+ int
40
+ bin_type_member_offset(char *type, char *member);
41
+
42
+ void
43
+ bin_update_image(int entry, char *trampee_addr, struct tramp_st2_entry *tramp);
83
44
  #endif
data/ext/elf.c CHANGED
@@ -1,47 +1,140 @@
1
1
  #if defined(HAVE_ELF)
2
-
2
+ #define _GNU_SOURCE
3
3
  #include "bin_api.h"
4
+ #include "arch.h"
4
5
 
6
+ #include <dwarf.h>
7
+ #include <err.h>
5
8
  #include <fcntl.h>
6
- #include <gelf.h>
9
+ #include <libdwarf.h>
10
+ #include <libelf/gelf.h>
7
11
  #include <link.h>
8
12
  #include <stdio.h>
13
+ #include <stdlib.h>
9
14
  #include <string.h>
10
15
  #include <sysexits.h>
11
16
  #include <unistd.h>
12
17
 
13
18
  #include <sys/mman.h>
14
19
 
15
- static ElfW(Shdr) symtab_shdr;
16
- static Elf *elf = NULL;
17
- static Elf_Data *symtab_data = NULL;
20
+ /* ruby binary info */
21
+ static int has_libruby = 0;
18
22
 
19
- void *
20
- bin_allocate_page()
23
+ static Dwarf_Debug dwrf = NULL;
24
+
25
+ static struct elf_info *ruby_info = NULL;
26
+
27
+ struct elf_info {
28
+ Elf *elf;
29
+
30
+ GElf_Addr base_addr;
31
+
32
+ void *text_segment;
33
+ size_t text_segment_len;
34
+
35
+ GElf_Addr relplt_addr;
36
+ Elf_Data *relplt;
37
+ size_t relplt_count;
38
+
39
+ GElf_Addr plt_addr;
40
+ Elf_Data *plt;
41
+ size_t plt_size;
42
+ size_t plt_count;
43
+
44
+ GElf_Ehdr ehdr;
45
+
46
+ Elf_Data *dynsym;
47
+ size_t dynsym_count;
48
+ const char *dynstr;
49
+
50
+ GElf_Shdr symtab_shdr;
51
+ Elf_Data *symtab_data;
52
+
53
+ const char *filename;
54
+ };
55
+
56
+
57
+ static void *
58
+ do_bin_allocate_page(void *cookie)
21
59
  {
22
- void * ret = NULL;
23
- ret = mmap(NULL, pagesize, PROT_WRITE|PROT_READ|PROT_EXEC, MAP_ANON|MAP_PRIVATE|MAP_32BIT, -1, 0);
60
+ void * ret = NULL, *addr = NULL;
61
+ struct elf_info *info = cookie;
62
+ uint16_t max = ~0, count = 0;
63
+
64
+ if (!info)
65
+ return NULL;
24
66
 
25
- if (ret != MAP_FAILED) {
26
- memset(ret, 0x90, pagesize);
67
+ if (has_libruby) {
68
+ addr = info->text_segment + info->text_segment_len;
69
+ for (; count < max;addr += pagesize, count += pagesize) {
70
+ ret = mmap(addr, pagesize, PROT_WRITE|PROT_READ|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
71
+ if (ret != MAP_FAILED) {
72
+ memset(ret, 0x90, pagesize);
73
+ return ret;
74
+ }
75
+ }
76
+ } else {
77
+ return mmap(NULL, pagesize, PROT_WRITE|PROT_READ|PROT_EXEC, MAP_ANON|MAP_PRIVATE|MAP_32BIT, -1, 0);
27
78
  }
28
79
 
29
- return ret;
80
+ return NULL;
30
81
  }
31
82
 
32
- void
33
- bin_update_image(int entry, void *trampee_addr)
83
+ void *
84
+ bin_allocate_page()
34
85
  {
35
- update_callqs(entry, trampee_addr);
86
+ return do_bin_allocate_page(ruby_info);
36
87
  }
37
88
 
38
- void *
39
- bin_find_symbol(char *sym, size_t *size)
89
+ static inline GElf_Addr
90
+ arch_plt_sym_val(struct elf_info *info, size_t ndx) {
91
+ return info->base_addr + info->plt_addr + (ndx + 1) * 16;
92
+ }
93
+
94
+ static void *
95
+ find_got_addr(char *symname, void *cookie)
96
+ {
97
+ size_t i = 0;
98
+ struct elf_info *info = cookie;
99
+
100
+ if (cookie == NULL) {
101
+ info = ruby_info;
102
+ }
103
+
104
+ for (i = 0; i < info->relplt_count; ++i) {
105
+ GElf_Rel rel;
106
+ GElf_Rela rela;
107
+ GElf_Sym sym;
108
+ GElf_Addr addr;
109
+ void *ret;
110
+ const char *name;
111
+
112
+ if (info->relplt->d_type == ELF_T_RELA) {
113
+ ret = gelf_getrela(info->relplt, i, &rela);
114
+
115
+ if (ret == NULL
116
+ || ELF64_R_SYM(rela.r_info) >= info->dynsym_count
117
+ || gelf_getsym(info->dynsym, ELF64_R_SYM(rela.r_info), &sym) == NULL)
118
+ return NULL;
119
+
120
+ name = info->dynstr + sym.st_name;
121
+ if (strcmp(symname, name) == 0) {
122
+ addr = arch_plt_sym_val(info, i);
123
+ return (void *)addr;
124
+ }
125
+ }
126
+ }
127
+
128
+ return NULL;
129
+ }
130
+
131
+ static void *
132
+ do_bin_find_symbol(char *sym, size_t *size, struct elf_info *elf)
40
133
  {
41
134
  char *name = NULL;
42
135
 
43
- ElfW(Sym) *esym = (ElfW(Sym)*) symtab_data->d_buf;
44
- ElfW(Sym) *lastsym = (ElfW(Sym)*) ((char*) symtab_data->d_buf + symtab_data->d_size);
136
+ ElfW(Sym) *esym = (ElfW(Sym)*) elf->symtab_data->d_buf;
137
+ ElfW(Sym) *lastsym = (ElfW(Sym)*) ((char*) elf->symtab_data->d_buf + elf->symtab_data->d_size);
45
138
 
46
139
  for (; esym < lastsym; esym++){
47
140
  /* ignore weak/numeric/empty symbols */
@@ -50,72 +143,413 @@ bin_find_symbol(char *sym, size_t *size)
50
143
  (ELF32_ST_BIND(esym->st_info)== STB_NUM))
51
144
  continue;
52
145
 
53
-
54
- name = elf_strptr(elf, symtab_shdr.sh_link, (size_t)esym->st_name);
146
+ name = elf_strptr(elf->elf, elf->symtab_shdr.sh_link, (size_t)esym->st_name);
55
147
  if (strcmp(name, sym) == 0) {
56
148
  if (size) {
57
149
  *size = esym->st_size;
58
150
  }
59
- return (void *)esym->st_value;
151
+ return elf->base_addr + (void *)esym->st_value;
60
152
  }
61
153
  }
62
154
  return NULL;
63
155
  }
64
156
 
157
+ void *
158
+ bin_find_symbol(char *sym, size_t *size)
159
+ {
160
+ return do_bin_find_symbol(sym, size, ruby_info);
161
+ }
65
162
 
66
163
  void
67
- bin_init()
164
+ bin_update_image(int entry, char *trampee, struct tramp_st2_entry *tramp)
68
165
  {
69
- int fd;
70
- ElfW(Shdr) shdr;
71
- size_t shstrndx;
72
- char *filename;
73
- Elf_Scn *scn;
166
+ void *trampee_addr = NULL;
167
+
168
+ if (!has_libruby) {
169
+ unsigned char *byte = ruby_info->text_segment;
170
+ trampee_addr = bin_find_symbol(trampee, NULL);
171
+ size_t count = 0;
172
+
173
+ for(; count < ruby_info->text_segment_len; byte++, count++) {
174
+ arch_insert_st1_tramp(byte, trampee_addr, tramp);
175
+ }
176
+ } else {
177
+ trampee_addr = find_got_addr(trampee, NULL);
178
+ arch_overwrite_got(trampee_addr, tramp->addr);
179
+ }
180
+ }
181
+
182
+
183
+ static Dwarf_Die
184
+ check_die(Dwarf_Die die, char *search, Dwarf_Half type)
185
+ {
186
+ char *name = 0;
187
+ Dwarf_Error error = 0;
188
+ Dwarf_Half tag = 0;
189
+ int ret = 0;
190
+ int res = dwarf_diename(die,&name,&error);
191
+ if (res == DW_DLV_ERROR) {
192
+ printf("Error in dwarf_diename\n");
193
+ exit(1);
194
+ }
195
+ if (res == DW_DLV_NO_ENTRY) {
196
+ return 0;
197
+ }
198
+
199
+ res = dwarf_tag(die,&tag,&error);
200
+ if (res != DW_DLV_OK) {
201
+ printf("Error in dwarf_tag\n");
202
+ exit(1);
203
+ }
204
+
205
+ if (tag == type && strcmp(name, search) == 0){
206
+ //printf("tag: %d name: '%s' die: %p\n",tag,name,die);
207
+ ret = 1;
208
+ }
209
+
210
+ dwarf_dealloc(dwrf,name,DW_DLA_STRING);
211
+
212
+ return ret ? die : 0;
213
+ }
214
+
215
+ static Dwarf_Die
216
+ search_dies(Dwarf_Die die, char *name, Dwarf_Half type)
217
+ {
218
+ int res = DW_DLV_ERROR;
219
+ Dwarf_Die cur_die=die;
220
+ Dwarf_Die child = 0;
221
+ Dwarf_Error error;
222
+ Dwarf_Die ret = 0;
223
+
224
+ ret = check_die(cur_die, name, type);
225
+ if (ret)
226
+ return ret;
227
+
228
+ for(;;) {
229
+ Dwarf_Die sib_die = 0;
230
+ res = dwarf_child(cur_die,&child,&error);
231
+ if (res == DW_DLV_ERROR) {
232
+ printf("Error in dwarf_child\n");
233
+ exit(1);
234
+ }
235
+ if (res == DW_DLV_OK) {
236
+ ret = search_dies(child,name,type);
237
+ if (ret) {
238
+ if (cur_die != die && cur_die != ret)
239
+ dwarf_dealloc(dwrf,cur_die,DW_DLA_DIE);
240
+ return ret;
241
+ }
242
+ }
243
+ /* res == DW_DLV_NO_ENTRY */
244
+
245
+ res = dwarf_siblingof(dwrf,cur_die,&sib_die,&error);
246
+ if (res == DW_DLV_ERROR) {
247
+ printf("Error in dwarf_siblingof\n");
248
+ exit(1);
249
+ }
250
+ if (res == DW_DLV_NO_ENTRY) {
251
+ /* Done at this level. */
252
+ break;
253
+ }
254
+ /* res == DW_DLV_OK */
255
+
256
+ if (cur_die != die)
257
+ dwarf_dealloc(dwrf,cur_die,DW_DLA_DIE);
258
+
259
+ cur_die = sib_die;
260
+ ret = check_die(cur_die, name, type);
261
+ if (ret)
262
+ return ret;
263
+ }
264
+ return 0;
265
+ }
266
+
267
+ static Dwarf_Die
268
+ find_die(char *name, Dwarf_Half type)
269
+ {
270
+ Dwarf_Die ret = 0;
271
+ Dwarf_Unsigned cu_header_length = 0;
272
+ Dwarf_Half version_stamp = 0;
273
+ Dwarf_Unsigned abbrev_offset = 0;
274
+ Dwarf_Half address_size = 0;
275
+ Dwarf_Unsigned next_cu_header = 0;
276
+ Dwarf_Error error;
277
+ int cu_number = 0;
278
+
279
+ Dwarf_Die no_die = 0;
280
+ Dwarf_Die cu_die = 0;
281
+ int res = DW_DLV_ERROR;
282
+
283
+ for (;;++cu_number) {
284
+ no_die = 0;
285
+ cu_die = 0;
286
+ res = DW_DLV_ERROR;
287
+
288
+ res = dwarf_next_cu_header(dwrf, &cu_header_length, &version_stamp, &abbrev_offset, &address_size, &next_cu_header, &error);
289
+
290
+ if (res == DW_DLV_ERROR) {
291
+ printf("Error in dwarf_next_cu_header\n");
292
+ exit(1);
293
+ }
294
+ if (res == DW_DLV_NO_ENTRY) {
295
+ /* Done. */
296
+ return 0;
297
+ }
298
+
299
+ /* The CU will have a single sibling, a cu_die. */
300
+ res = dwarf_siblingof(dwrf,no_die,&cu_die,&error);
301
+
302
+ if (res == DW_DLV_ERROR) {
303
+ printf("Error in dwarf_siblingof on CU die \n");
304
+ exit(1);
305
+ }
306
+ if (res == DW_DLV_NO_ENTRY) {
307
+ /* Impossible case. */
308
+ printf("no entry! in dwarf_siblingof on CU die \n");
309
+ exit(1);
310
+ }
311
+
312
+ ret = search_dies(cu_die,name,type);
313
+
314
+ if (cu_die != ret)
315
+ dwarf_dealloc(dwrf,cu_die,DW_DLA_DIE);
316
+
317
+ if (ret)
318
+ break;
319
+ }
320
+
321
+ /* traverse to the end to reset */
322
+ while ((dwarf_next_cu_header(dwrf, &cu_header_length, &version_stamp, &abbrev_offset, &address_size, &next_cu_header, &error)) != DW_DLV_NO_ENTRY);
323
+
324
+ return ret ? ret : 0;
325
+ }
326
+
327
+ static int
328
+ bin_has_libruby(struct elf_info *cookie)
329
+ {
330
+ struct link_map *map = _r_debug.r_map;
331
+ struct elf_info *lib = cookie;
332
+
333
+ if (has_libruby != -1) {
334
+ has_libruby = 0;
335
+ while (map) {
336
+ if (strstr(map->l_name, "libruby.so")) {
337
+ if (lib) {
338
+ lib->base_addr = (GElf_Addr)map->l_addr;
339
+ lib->filename = strdup(map->l_name);
340
+ }
341
+ has_libruby = 1;
342
+ break;
343
+ }
344
+ map = map->l_next;
345
+ }
346
+ }
347
+
348
+ return has_libruby;
349
+ }
350
+
351
+ int
352
+ bin_type_size(char *name)
353
+ {
354
+ Dwarf_Unsigned size = 0;
355
+ Dwarf_Error error;
356
+ int res = DW_DLV_ERROR;
357
+ Dwarf_Die die = 0;
358
+
359
+ die = find_die(name, DW_TAG_structure_type);
360
+
361
+ if (die) {
362
+ res = dwarf_bytesize(die, &size, &error);
363
+ dwarf_dealloc(dwrf,die,DW_DLA_DIE);
364
+ if (res == DW_DLV_OK)
365
+ return (int)size;
366
+ }
367
+
368
+ return -1;
369
+ }
370
+
371
+ int
372
+ bin_type_member_offset(char *type, char *member)
373
+ {
374
+ Dwarf_Error error;
375
+ int res = DW_DLV_ERROR;
376
+ Dwarf_Die die = 0, child = 0;
377
+ Dwarf_Attribute attr = 0;
378
+
379
+ die = find_die(type, DW_TAG_structure_type);
380
+
381
+ if (die) {
382
+ child = search_dies(die, member, DW_TAG_member);
383
+ dwarf_dealloc(dwrf,die,DW_DLA_DIE);
384
+
385
+ if (child) {
386
+ res = dwarf_attr(child, DW_AT_data_member_location, &attr, &error);
387
+ if (res == DW_DLV_OK) {
388
+ Dwarf_Locdesc *locs = 0;
389
+ Dwarf_Signed num = 0;
390
+
391
+ res = dwarf_loclist(attr, &locs, &num, &error);
392
+ if (res == DW_DLV_OK && num > 0) {
393
+ return locs[0].ld_s[0].lr_number;
394
+ }
395
+ }
396
+ }
397
+ }
398
+
399
+ return -1;
400
+ }
401
+
402
+ static Elf *
403
+ open_elf(const char *filename)
404
+ {
405
+ Elf *ret = NULL;
406
+ int fd = 0;
74
407
 
75
408
  if (elf_version(EV_CURRENT) == EV_NONE)
76
409
  errx(EX_SOFTWARE, "ELF library initialization failed: %s",
77
410
  elf_errmsg(-1));
78
411
 
79
- asprintf(&filename, "/proc/%ld/exe", (long)getpid());
80
-
81
412
  if ((fd = open(filename, O_RDONLY, 0)) < 0)
82
413
  err(EX_NOINPUT, "open \%s\" failed", filename);
83
414
 
84
- if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
415
+ if ((ret = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
85
416
  errx(EX_SOFTWARE, "elf_begin() failed: %s.",
86
417
  elf_errmsg(-1));
87
418
 
88
- if (elf_kind(elf) != ELF_K_ELF)
419
+ if (elf_kind(ret) != ELF_K_ELF)
89
420
  errx(EX_DATAERR, "%s is not an ELF object.", filename);
90
421
 
422
+ return ret;
423
+ }
424
+
425
+ static void
426
+ dissect_elf(struct elf_info *info)
427
+ {
428
+ size_t shstrndx = 0;
429
+ Elf *elf = info->elf;
430
+ ElfW(Dyn) *dyn;
431
+ Elf_Scn *scn = NULL;
432
+ GElf_Shdr shdr;
433
+ size_t j = 0;
434
+
91
435
  if (elf_getshdrstrndx(elf, &shstrndx) == -1)
92
- errx(EX_SOFTWARE, "getshstrndx() failed: %s.",
93
- elf_errmsg(-1));
436
+ errx(EX_SOFTWARE, "getshstrndx() failed: %s.", elf_errmsg(-1));
94
437
 
95
- scn = NULL;
438
+ if (gelf_getehdr(elf, &(info->ehdr)) == NULL)
439
+ errx(EX_SOFTWARE, "Couldn't get elf header.");
96
440
 
97
441
  while ((scn = elf_nextscn(elf, scn)) != NULL) {
98
442
  if (gelf_getshdr(scn, &shdr) != &shdr)
99
443
  errx(EX_SOFTWARE, "getshdr() failed: %s.",
100
444
  elf_errmsg(-1));
101
445
 
102
- if (shdr.sh_type == SHT_PROGBITS &&
446
+ /* if there is a dynamic section ... */
447
+ if (shdr.sh_type == SHT_DYNAMIC) {
448
+ Elf_Data *data;
449
+ data = elf_getdata(scn, NULL);
450
+ /* for each entry in the dyn section... */
451
+ for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
452
+ GElf_Dyn dyn;
453
+ if (gelf_getdyn(data, j, &dyn) == NULL) {
454
+ error(EXIT_FAILURE, 0,
455
+ "Couldn't get .dynamic data from loaded library.");
456
+ }
457
+
458
+ if (dyn.d_tag == DT_JMPREL) {
459
+ info->relplt_addr = dyn.d_un.d_ptr;
460
+ }
461
+ else if (dyn.d_tag == DT_PLTRELSZ) {
462
+ info->plt_size = dyn.d_un.d_val;
463
+ }
464
+ }
465
+ } else if (shdr.sh_type == SHT_DYNSYM) {
466
+ Elf_Data *data;
467
+
468
+ info->dynsym = elf_getdata(scn, NULL);
469
+ info->dynsym_count = shdr.sh_size / shdr.sh_entsize;
470
+ if (info->dynsym == NULL
471
+ || elf_getdata(scn, info->dynsym) != NULL)
472
+ error(EXIT_FAILURE, 0,
473
+ "Couldn't get .dynsym data ");
474
+
475
+ scn = elf_getscn(elf, shdr.sh_link);
476
+ if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
477
+ error(EXIT_FAILURE, 0,
478
+ "Couldn't get section header from");
479
+
480
+ data = elf_getdata(scn, NULL);
481
+ if (data == NULL || elf_getdata(scn, data) != NULL
482
+ || shdr.sh_size != data->d_size || data->d_off)
483
+ error(EXIT_FAILURE, 0,
484
+ "Couldn't get .dynstr data");
485
+
486
+ info->dynstr = data->d_buf;
487
+ } else if (shdr.sh_type == SHT_PROGBITS &&
103
488
  (shdr.sh_flags == (SHF_ALLOC | SHF_EXECINSTR)) &&
104
489
  strcmp(elf_strptr(elf, shstrndx, shdr.sh_name), ".text") == 0) {
105
490
 
106
- text_segment = (void *)shdr.sh_addr;
107
- text_segment_len = shdr.sh_size;
491
+ info->text_segment = (void *)shdr.sh_addr + info->base_addr;
492
+ info->text_segment_len = shdr.sh_size;
493
+ } else if (shdr.sh_type == SHT_PROGBITS) {
494
+ if (strcmp(elf_strptr(elf, shstrndx, shdr.sh_name), ".plt") == 0) {
495
+ info->plt_addr = shdr.sh_addr;
496
+ }
108
497
  } else if (shdr.sh_type == SHT_SYMTAB) {
109
- symtab_shdr = shdr;
110
- if ((symtab_data = elf_getdata(scn,symtab_data)) == NULL || symtab_data->d_size == 0) {
111
- errx(EX_DATAERR, "ruby has a broken symbol table. Is it stripped? "
112
- "memprof only works on binaries that are not stripped!\n", filename);
113
- }
498
+ info->symtab_shdr = shdr;
499
+ if ((info->symtab_data = elf_getdata(scn, info->symtab_data)) == NULL ||
500
+ info->symtab_data->d_size == 0) {
501
+ errx(EX_DATAERR, "shared lib has a broken symbol table. Is it stripped? "
502
+ "memprof only works on shared libs that are not stripped!");
503
+ }
504
+ }
505
+ }
506
+
507
+ if (!info->symtab_data) {
508
+ errx(EX_DATAERR, "binary is stripped. memprof only works on binaries that are not stripped!");
509
+ }
510
+
511
+
512
+ for (j = 1; j < info->ehdr.e_shnum; j++) {
513
+ scn = elf_getscn(elf, j);
514
+ if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL)
515
+ error(EXIT_FAILURE, 0,
516
+ "Couldn't get section header from library.");
517
+
518
+ if (shdr.sh_addr == info->relplt_addr
519
+ && shdr.sh_size == info->plt_size) {
520
+ info->relplt = elf_getdata(scn, NULL);
521
+ info->relplt_count = shdr.sh_size / shdr.sh_entsize;
522
+ if (info->relplt == NULL
523
+ || elf_getdata(scn, info->relplt) != NULL)
524
+ error(EXIT_FAILURE, 0,
525
+ "Couldn't get .rel*.plt data from");
526
+ break;
114
527
  }
115
528
  }
116
529
 
117
- if (!symtab_data) {
118
- errx(EX_DATAERR, "binary is stripped. memprof only works on binaries that are not stripped!", filename);
530
+ return;
531
+ }
532
+
533
+ void
534
+ bin_init()
535
+ {
536
+ Dwarf_Error dwrf_err;
537
+
538
+ ruby_info = malloc(sizeof(*ruby_info));
539
+
540
+ if (!ruby_info)
541
+ return;
542
+
543
+ if (!bin_has_libruby(ruby_info)) {
544
+ ruby_info->filename = strdup("/proc/self/exe");
545
+ ruby_info->base_addr = 0;
546
+ }
547
+
548
+ ruby_info->elf = open_elf(ruby_info->filename);
549
+ dissect_elf(ruby_info);
550
+
551
+ if (dwarf_elf_init(ruby_info->elf, DW_DLC_READ, NULL, NULL, &dwrf, &dwrf_err) != DW_DLV_OK) {
552
+ errx(EX_DATAERR, "unable to read debugging data from binary. was it compiled with -g? is it unstripped?");
119
553
  }
120
554
  }
121
555
  #endif