memprof 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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