heap_dump 0.0.25 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ .DS_Store
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # HeapDump
2
2
 
3
3
  Low-level ruby heap memory dump - including data and code references.
4
- Written across ruby 1.9.2-p290 data structures. Other rubies support may come later (or may not).
4
+ Originally written across ruby 1.9.2-p290 data structures.
5
+
6
+ Does work on other 1.9.2s and 1.9.3, but not well-tested yet(output is not proven to be as full etc.).
5
7
 
6
8
  Currently is under development and output format may differ.
7
9
 
@@ -31,6 +31,10 @@ spec = instance_eval(File.read(gemspec), gemspec).dependencies.find{|d|d.name ==
31
31
  yajl = find_gem_dir(spec.name, spec.requirement)
32
32
  find_header('api/yajl_gen.h', File.join(yajl, 'ext', 'yajl'))
33
33
 
34
+ #TODO: inject ruby version
35
+ unless find_header("gc_internal.h", File.join(File.dirname(__FILE__),'specific', "ruby-#{RUBY_VERSION}")) && have_header("gc_internal.h")
36
+ raise "Do not have internal structs for your ruby version"
37
+ end
34
38
 
35
39
  hdrs = proc {
36
40
  res = %w{
@@ -45,6 +49,7 @@ hdrs = proc {
45
49
  #optional:
46
50
  %w{
47
51
  constant.h
52
+ internal.h
48
53
  }.each{|h| have_header(h)}
49
54
 
50
55
  res
@@ -4,19 +4,10 @@
4
4
 
5
5
 
6
6
  #ifdef HAVE_CONSTANT_H
7
- //have this in 1.9.3+, for future compatibility
7
+ //have this in 1.9.3
8
8
  #include "constant.h"
9
9
  #else
10
- //from 1.9.2
11
- typedef enum {
12
- CONST_PUBLIC = 0x00,
13
- CONST_PRIVATE = 0x01
14
- } rb_const_flag_t;
15
-
16
- typedef struct rb_const_entry_struct {
17
- rb_const_flag_t flag;
18
- VALUE value; /* should be mark */
19
- } rb_const_entry_t;
10
+ #include "internal_constant.h"
20
11
  #endif
21
12
 
22
13
  #include "node.h"
@@ -24,10 +15,25 @@
24
15
  // #include "atomic.h"
25
16
  #include "iseq.h"
26
17
 
18
+ #ifdef HAVE_INTERNAL_H
19
+ #include "internal.h"
20
+ #else
27
21
  #define RCLASS_EXT(c) (RCLASS(c)->ptr)
22
+ #endif
28
23
 
29
24
  #define NODE_OP_ASGN2_ARG NODE_LAST + 1
30
25
 
26
+ #ifndef FALSE
27
+ # define FALSE 0
28
+ #elif FALSE
29
+ # error FALSE must be false
30
+ #endif
31
+ #ifndef TRUE
32
+ # define TRUE 1
33
+ #elif !TRUE
34
+ # error TRUE must be true
35
+ #endif
36
+
31
37
  #include "method.h"
32
38
 
33
39
  #include "ruby_io.h" // need rb_io_t
@@ -40,6 +46,18 @@
40
46
 
41
47
  // simple test - rake compile && bundle exec ruby -e 'require "heap_dump"; HeapDump.dump'
42
48
 
49
+
50
+ #ifdef HAVE_GC_INTERNAL_H
51
+ #include "gc_internal.h"
52
+ #else
53
+ #error No internal gc header for your ruby
54
+ //TODO: just do not dump something?
55
+ #endif
56
+
57
+ #include "fiber.h"
58
+ #include "internal_typed_data.h"
59
+
60
+
43
61
  static VALUE rb_mHeapDumpModule;
44
62
 
45
63
  static ID classid;
@@ -86,7 +104,7 @@ static void flush_yajl(walk_ctx_t *ctx){
86
104
  }
87
105
  }
88
106
 
89
- static inline int is_pointer_to_heap(void *ptr, void* osp);
107
+ static inline int is_in_heap(void *ptr, void* osp);
90
108
 
91
109
  static inline const char* rb_builtin_type(VALUE obj){
92
110
  switch(BUILTIN_TYPE(obj)){
@@ -351,7 +369,7 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
351
369
  unsigned long n = obj->u3.cnt;
352
370
  while (n--) {
353
371
  //v = *x;
354
- // if (is_pointer_to_heap(objspace, (void *)v)) {
372
+ // if (is_in_heap((void *)v), objspace) {
355
373
  // //gc_mark(objspace, v, 0);
356
374
  yg_id(*x);
357
375
  // }
@@ -383,12 +401,12 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
383
401
  //iteration func - blocks,procs,lambdas etc:
384
402
  case NODE_IFUNC: //NEN_CFNC, NEN_TVAL, NEN_STATE? / u2 seems to be data for func(context?)
385
403
  //printf("IFUNC NODE: %p %p %p\n", obj->nd_cfnc, obj->u2.node, (void*)obj->nd_aid /*u3 - aid id- - aka frame_this_func?*/);
386
- if(is_pointer_to_heap(obj->u2.node, 0)){
404
+ if(is_in_heap(obj->u2.node, 0)){
387
405
  //printf("in heap: %p\n", obj->u2.node);
388
406
  //TODO: do we need to dump it inline?
389
407
  yg_id((VALUE)obj->u2.node);
390
408
  }
391
- if(is_pointer_to_heap( (void*)obj->nd_aid, 0)){
409
+ if(is_in_heap( (void*)obj->nd_aid, 0)){
392
410
  //printf("in heap: %p\n", (void*)obj->nd_aid);
393
411
  yg_id(obj->nd_aid);
394
412
  }
@@ -403,9 +421,9 @@ static void dump_node_refs(NODE* obj, walk_ctx_t* ctx){
403
421
  printf("UNKNOWN NODE TYPE %d(%s): %p %p %p\n", nd_type(obj), node_type_name(obj), (void*)obj->u1.node, (void*)obj->u2.node, (void*)obj->u3.node);
404
422
  }
405
423
 
406
- // if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) { gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); }
407
- // if (is_pointer_to_heap(objspace, obj->as.node.u2.node)) { gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev); }
408
- // if (is_pointer_to_heap(objspace, obj->as.node.u3.node)) { gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev); }
424
+ // if (is_in_heap(obj->as.node.u1.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev); }
425
+ // if (is_in_heap(obj->as.node.u2.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u2.node, lev); }
426
+ // if (is_in_heap(obj->as.node.u3.node, objspace)) { gc_mark(objspace, (VALUE)obj->as.node.u3.node, lev); }
409
427
 
410
428
  //yg_id((VALUE)obj->u1.node);
411
429
  //yg_id((VALUE)obj->u2.node);
@@ -586,58 +604,6 @@ static void dump_block(const rb_block_t* block, walk_ctx_t *ctx){
586
604
  }
587
605
 
588
606
 
589
- #define CAPTURE_JUST_VALID_VM_STACK 1
590
-
591
- enum context_type {
592
- CONTINUATION_CONTEXT = 0,
593
- FIBER_CONTEXT = 1,
594
- ROOT_FIBER_CONTEXT = 2
595
- };
596
-
597
- typedef struct rb_context_struct {
598
- enum context_type type;
599
- VALUE self;
600
- int argc;
601
- VALUE value;
602
- VALUE *vm_stack;
603
- #ifdef CAPTURE_JUST_VALID_VM_STACK
604
- size_t vm_stack_slen; /* length of stack (head of th->stack) */
605
- size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
606
- #endif
607
- VALUE *machine_stack;
608
- VALUE *machine_stack_src;
609
- #ifdef __ia64
610
- VALUE *machine_register_stack;
611
- VALUE *machine_register_stack_src;
612
- int machine_register_stack_size;
613
- #endif
614
- rb_thread_t saved_thread;
615
- rb_jmpbuf_t jmpbuf;
616
- size_t machine_stack_size;
617
- } rb_context_t;
618
-
619
-
620
-
621
- enum fiber_status {
622
- CREATED,
623
- RUNNING,
624
- TERMINATED
625
- };
626
-
627
- ///TODO: move this out
628
- typedef struct rb_fiber_struct {
629
- rb_context_t cont;
630
- VALUE prev;
631
- enum fiber_status status;
632
- struct rb_fiber_struct *prev_fiber;
633
- struct rb_fiber_struct *next_fiber;
634
- } rb_fiber_t;
635
-
636
-
637
-
638
-
639
-
640
-
641
607
 
642
608
  static void yg_fiber_status(enum fiber_status status, walk_ctx_t* ctx){
643
609
  switch(status){
@@ -660,7 +626,7 @@ static void dump_locations(VALUE* p, long int n, walk_ctx_t *ctx){
660
626
  VALUE* x = p;
661
627
  while(n--){
662
628
  VALUE v = *x;
663
- if(is_pointer_to_heap((void*)v, NULL)) //TODO: sometimes thread is known, may get its th->vm->objspace (in case there's a few)
629
+ if(is_in_heap((void*)v, NULL)) //TODO: sometimes thread is known, may get its th->vm->objspace (in case there's a few)
664
630
  yg_id(v);
665
631
  x++;
666
632
  }
@@ -683,15 +649,6 @@ vm_dump_each_thread_func(st_data_t key, VALUE obj, walk_ctx_t *ctx){
683
649
  return ST_CONTINUE;
684
650
  }
685
651
 
686
- //FIXME: parse this from ruby source!
687
- struct METHOD {
688
- //for 1.9.2 only
689
- VALUE recv;
690
- VALUE rclass;
691
- ID id;
692
- rb_method_entry_t me;
693
- };
694
-
695
652
 
696
653
  static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
697
654
 
@@ -757,9 +714,9 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
757
714
  ygh_int("method_id", data->id);
758
715
 
759
716
  yg_cstring("method");
760
- if(data->me.def){
717
+ if(METHOD_DEFINITIONP(data)){
761
718
  //printf("methof def %p\n", &data->me);
762
- dump_method_definition_as_value(data->me.def, ctx);
719
+ dump_method_definition_as_value(METHOD_DEFINITIONP(data), ctx);
763
720
  //printf("meth end\n");
764
721
  }
765
722
  return;
@@ -794,27 +751,6 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
794
751
  return;
795
752
  }
796
753
 
797
- //FIXME: autogen this:
798
- struct enumerator {
799
- VALUE obj;
800
- ID meth;
801
- VALUE args;
802
- VALUE fib;
803
- VALUE dst;
804
- VALUE lookahead;
805
- VALUE feedvalue;
806
- VALUE stop_exc;
807
- };
808
-
809
- struct generator {
810
- VALUE proc;
811
- };
812
-
813
- struct yielder {
814
- VALUE proc;
815
- };
816
- // end of fixme
817
-
818
754
  if(!strcmp("enumerator", typename)){
819
755
  struct enumerator *ptr = RTYPEDDATA_DATA(obj);
820
756
  ygh_id("obj", ptr->obj);
@@ -929,12 +865,6 @@ static void dump_data_if_known(VALUE obj, walk_ctx_t *ctx){
929
865
  return;
930
866
  }
931
867
 
932
- //FIXME: autogen this from ruby (this copied from 1.9.2p290)
933
- struct thgroup {
934
- int enclosed;
935
- VALUE group;
936
- };
937
-
938
868
  if(!strcmp("thgroup", typename)){
939
869
  const struct thgroup* gr = RTYPEDDATA_DATA(obj);
940
870
  ygh_id("group", gr->group);
@@ -1150,10 +1080,11 @@ static inline void walk_live_object(VALUE obj, walk_ctx_t *ctx){
1150
1080
  case T_DATA: // data of extensions + raw bytecode etc., refs undumpable? maybe in some way mess with mark callback? (need to intercept rb_gc_mark :( )
1151
1081
  if(RTYPEDDATA_P(obj)){
1152
1082
  ygh_cstring("type_name", RTYPEDDATA_TYPE(obj)->wrap_struct_name);
1153
- if(RTYPEDDATA_TYPE(obj)->dsize){
1154
- ygh_int("size", RTYPEDDATA_TYPE(obj)->dsize(RTYPEDDATA_DATA(obj)));
1155
- }
1156
-
1083
+ #if HAVE_RB_DATA_TYPE_T_FUNCTION
1084
+ if(RTYPEDDATA_TYPE(obj)->function.dsize) ygh_int("size", RTYPEDDATA_TYPE(obj)->function.dsize(RTYPEDDATA_DATA(obj)));
1085
+ #else
1086
+ if(RTYPEDDATA_TYPE(obj)->dsize) ygh_int("size", RTYPEDDATA_TYPE(obj)->dsize(RTYPEDDATA_DATA(obj)));
1087
+ #endif
1157
1088
  dump_data_if_known(obj, ctx);
1158
1089
  }
1159
1090
  break;
@@ -1255,276 +1186,15 @@ ruby_get_stack_grow_direction(volatile VALUE *addr)
1255
1186
 
1256
1187
  #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
1257
1188
 
1258
- extern st_table *rb_class_tbl;
1259
-
1260
1189
 
1261
1190
  /////////////
1262
- #define MARK_STACK_MAX 1024
1263
-
1264
- #ifndef CALC_EXACT_MALLOC_SIZE
1265
- #define CALC_EXACT_MALLOC_SIZE 0
1266
- #endif
1267
- #include "ruby/re.h"
1268
-
1269
- #ifndef FALSE
1270
- # define FALSE 0
1271
- #elif FALSE
1272
- # error FALSE must be false
1273
- #endif
1274
- #ifndef TRUE
1275
- # define TRUE 1
1276
- #elif !TRUE
1277
- # error TRUE must be true
1278
- #endif
1279
-
1280
- //FIXME: this should be autoextracted from ruby
1281
- // see how this is done in ruby-internal gem
1282
- typedef struct RVALUE {
1283
- union {
1284
- struct {
1285
- VALUE flags; /* always 0 for freed obj */
1286
- struct RVALUE *next;
1287
- } free;
1288
- struct RBasic basic;
1289
- struct RObject object;
1290
- struct RClass klass;
1291
- struct RFloat flonum;
1292
- struct RString string;
1293
- struct RArray array;
1294
- struct RRegexp regexp;
1295
- struct RHash hash;
1296
- struct RData data;
1297
- struct RTypedData typeddata;
1298
- struct RStruct rstruct;
1299
- struct RBignum bignum;
1300
- struct RFile file;
1301
- struct RNode node;
1302
- struct RMatch match;
1303
- struct RRational rational;
1304
- struct RComplex complex;
1305
- } as;
1306
- #ifdef GC_DEBUG
1307
- const char *file;
1308
- int line;
1309
- #endif
1310
- } RVALUE;
1311
-
1312
- typedef struct gc_profile_record {
1313
- double gc_time;
1314
- double gc_mark_time;
1315
- double gc_sweep_time;
1316
- double gc_invoke_time;
1317
-
1318
- size_t heap_use_slots;
1319
- size_t heap_live_objects;
1320
- size_t heap_free_objects;
1321
- size_t heap_total_objects;
1322
- size_t heap_use_size;
1323
- size_t heap_total_size;
1324
-
1325
- int have_finalize;
1326
- int is_marked;
1327
-
1328
- size_t allocate_increase;
1329
- size_t allocate_limit;
1330
- } gc_profile_record;
1331
-
1332
- struct heaps_slot {
1333
- void *membase;
1334
- RVALUE *slot;
1335
- size_t limit;
1336
- uintptr_t *bits;
1337
- RVALUE *freelist;
1338
- struct heaps_slot *next;
1339
- struct heaps_slot *prev;
1340
- struct heaps_slot *free_next;
1341
- };
1342
-
1343
- struct heaps_header {
1344
- struct heaps_slot *base;
1345
- uintptr_t *bits;
1346
- };
1347
-
1348
- struct sorted_heaps_slot {
1349
- RVALUE *start;
1350
- RVALUE *end;
1351
- struct heaps_slot *slot;
1352
- };
1353
-
1354
- struct heaps_free_bitmap {
1355
- struct heaps_free_bitmap *next;
1356
- };
1357
-
1358
- struct gc_list {
1359
- VALUE *varptr;
1360
- struct gc_list *next;
1361
- };
1362
-
1363
-
1364
- // typedef struct rb_objspace {
1365
- // struct {
1366
- // size_t limit;
1367
- // size_t increase;
1368
- // //FIXME: this should match ruby settings
1369
- // //#if CALC_EXACT_MALLOC_SIZE
1370
- // size_t allocated_size;
1371
- // size_t allocations;
1372
- // //#endif
1373
- // } malloc_params;
1374
-
1375
- // struct {
1376
- // size_t increment;
1377
- // struct heaps_slot *ptr;
1378
- // struct heaps_slot *sweep_slots;
1379
- // struct heaps_slot *free_slots;
1380
- // struct sorted_heaps_slot *sorted;
1381
- // size_t length;
1382
- // size_t used;
1383
- // struct heaps_free_bitmap *free_bitmap;
1384
- // RVALUE *range[2];
1385
- // RVALUE *freed;
1386
- // size_t live_num;
1387
- // size_t free_num;
1388
- // size_t free_min;
1389
- // size_t final_num;
1390
- // size_t do_heap_free;
1391
- // } heap;
1392
-
1393
- // struct {
1394
- // int dont_gc;
1395
- // int dont_lazy_sweep;
1396
- // int during_gc;
1397
- // rb_atomic_t finalizing;
1398
- // } flags;
1399
-
1400
- // struct {
1401
- // st_table *table;
1402
- // RVALUE *deferred;
1403
- // } final;
1404
-
1405
- // struct {
1406
- // VALUE buffer[MARK_STACK_MAX];
1407
- // VALUE *ptr;
1408
- // int overflow;
1409
- // } markstack;
1410
-
1411
- // struct {
1412
- // int run;
1413
- // gc_profile_record *record;
1414
- // size_t count;
1415
- // size_t size;
1416
- // double invoke_time;
1417
- // } profile;
1418
-
1419
- // struct gc_list *global_list;
1420
- // size_t count;
1421
- // int gc_stress;
1422
- // } rb_objspace_t;
1423
-
1424
-
1425
- // 1.9.2-p290:
1426
- typedef struct rb_objspace {
1427
- struct {
1428
- size_t limit;
1429
- size_t increase;
1430
- #if CALC_EXACT_MALLOC_SIZE
1431
- size_t allocated_size;
1432
- size_t allocations;
1433
- #endif
1434
- } malloc_params;
1435
- struct {
1436
- size_t increment;
1437
- struct heaps_slot *ptr;
1438
- size_t length;
1439
- size_t used;
1440
- RVALUE *freelist;
1441
- RVALUE *range[2];
1442
- RVALUE *freed;
1443
- } heap;
1444
- struct {
1445
- int dont_gc;
1446
- int during_gc;
1447
- } flags;
1448
- struct {
1449
- st_table *table;
1450
- RVALUE *deferred;
1451
- } final;
1452
- struct {
1453
- VALUE buffer[MARK_STACK_MAX];
1454
- VALUE *ptr;
1455
- int overflow;
1456
- } markstack;
1457
- struct {
1458
- int run;
1459
- gc_profile_record *record;
1460
- size_t count;
1461
- size_t size;
1462
- double invoke_time;
1463
- } profile;
1464
- struct gc_list *global_list;
1465
- unsigned int count;
1466
- int gc_stress;
1467
- } rb_objspace_t;
1468
-
1469
- #define malloc_limit objspace->malloc_params.limit
1470
- #define malloc_increase objspace->malloc_params.increase
1471
- #define heaps objspace->heap.ptr
1472
- #define heaps_length objspace->heap.length
1473
- #define heaps_used objspace->heap.used
1474
- #define lomem objspace->heap.range[0]
1475
- #define himem objspace->heap.range[1]
1476
- #define heaps_inc objspace->heap.increment
1477
- #define heaps_freed objspace->heap.freed
1478
- #define dont_gc objspace->flags.dont_gc
1479
- #define during_gc objspace->flags.during_gc
1480
- #define finalizing objspace->flags.finalizing
1481
- #define finalizer_table objspace->final.table
1482
- #define deferred_final_list objspace->final.deferred
1483
- #define mark_stack objspace->markstack.buffer
1484
- #define mark_stack_ptr objspace->markstack.ptr
1485
- #define mark_stack_overflow objspace->markstack.overflow
1486
- #define global_List objspace->global_list
1487
-
1488
- #define RANY(o) ((RVALUE*)(o))
1489
-
1490
- static inline int
1491
- is_pointer_to_heap(void *ptr, void* osp)
1492
- {
1493
- rb_objspace_t *objspace = osp;
1494
- if(!ptr) return false;
1495
- if(!objspace) objspace = GET_THREAD()->vm->objspace;
1496
1191
 
1497
- register RVALUE *p = RANY(ptr);
1498
- //register struct sorted_heaps_slot *heap;
1499
- register size_t hi, lo, mid;
1500
1192
 
1501
- if (p < lomem || p > himem) {
1502
- //printf("not in range %p - %p (objspace %p, l%u used %u)\n", lo, hi, objspace, heaps_length, heaps_used);
1503
- return FALSE;
1504
- }
1505
- //printf("ptr in range\n");
1506
- if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
1507
- //printf("ptr %p align correct\n", ptr);
1508
-
1509
- //1.9.2-p290
1510
- /* check if p looks like a pointer using bsearch*/
1511
- lo = 0;
1512
- hi = heaps_used;
1513
- while (lo < hi) {
1514
- mid = (lo + hi) / 2;
1515
- register struct heaps_slot *heap;
1516
- heap = &heaps[mid];
1517
- if (heap->slot <= p) {
1518
- if (p < heap->slot + heap->limit)
1519
- return TRUE;
1520
- lo = mid + 1;
1521
- }
1522
- else {
1523
- hi = mid;
1524
- }
1525
- }
1526
- //printf("not found");
1527
- return FALSE;
1193
+ static inline int is_in_heap(void *ptr, void* osp){
1194
+ rb_objspace_t *objspace = osp;
1195
+ if(!ptr) return false;
1196
+ if(!objspace) objspace = GET_THREAD()->vm->objspace;
1197
+ return is_pointer_to_heap(objspace, ptr);
1528
1198
  }
1529
1199
 
1530
1200
 
@@ -1581,7 +1251,7 @@ vm_backtrace_each(const rb_thread_t *th, int lev, void (*init)(void *), rb_backt
1581
1251
  }
1582
1252
  else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
1583
1253
  ID id;
1584
- extern VALUE ruby_engine_name;
1254
+
1585
1255
 
1586
1256
  if (NIL_P(file)) file = ruby_engine_name;
1587
1257
  if (cfp->me->def)
@@ -1735,7 +1405,7 @@ static void dump_machine_context(walk_ctx_t *ctx){
1735
1405
  //printf("registers\n");
1736
1406
  while (n--) {
1737
1407
  VALUE v = *(x++);
1738
- if(is_pointer_to_heap((void*)v, NULL))
1408
+ if(is_in_heap((void*)v, NULL))
1739
1409
  yg_id(v);
1740
1410
  }
1741
1411
  yajl_gen_array_close(ctx->yajl);
@@ -1751,7 +1421,7 @@ static void dump_machine_context(walk_ctx_t *ctx){
1751
1421
  VALUE v = *(x++);
1752
1422
  //printf("val: %p\n", (void*)v);
1753
1423
  //FIXME: other objspace (not default one?)
1754
- if(is_pointer_to_heap((void*)v, NULL)) {
1424
+ if(is_in_heap((void*)v, NULL)) {
1755
1425
  //printf("ON heap\n");
1756
1426
  yg_id(v);
1757
1427
  }
@@ -1773,7 +1443,7 @@ static int dump_iv_entry1(ID key, rb_const_entry_t* ce/*st_data_t val*/, walk_ct
1773
1443
 
1774
1444
  //printf("name %s\n", RSTRING_PTR(rb_class_path(rb_class_real_checked(value))));
1775
1445
 
1776
- //if(is_pointer_to_heap(value, NULL)){
1446
+ //if(is_in_heap(value, NULL)){
1777
1447
  //printf("on heap\n");
1778
1448
  yg_id(value);
1779
1449
  //}
@@ -1827,6 +1497,7 @@ void heapdump_dump(const char* filename){
1827
1497
  //printf("global %p\n", v);
1828
1498
  }
1829
1499
 
1500
+ #ifdef HAVE_RB_CLASS_TBL
1830
1501
  yg_cstring("classes");
1831
1502
  yajl_gen_array_open(ctx->yajl);
1832
1503
  printf("classes\n");
@@ -1835,6 +1506,7 @@ void heapdump_dump(const char* filename){
1835
1506
  else printf("no classes\n");
1836
1507
  yajl_gen_array_close(ctx->yajl);
1837
1508
  flush_yajl(ctx);
1509
+ #endif
1838
1510
 
1839
1511
  //try_dump_generic_ivars();
1840
1512
 
@@ -0,0 +1,48 @@
1
+ //1.9.2
2
+
3
+ #define CAPTURE_JUST_VALID_VM_STACK 1
4
+
5
+ enum context_type {
6
+ CONTINUATION_CONTEXT = 0,
7
+ FIBER_CONTEXT = 1,
8
+ ROOT_FIBER_CONTEXT = 2
9
+ };
10
+
11
+ typedef struct rb_context_struct {
12
+ enum context_type type;
13
+ VALUE self;
14
+ int argc;
15
+ VALUE value;
16
+ VALUE *vm_stack;
17
+ #ifdef CAPTURE_JUST_VALID_VM_STACK
18
+ size_t vm_stack_slen; /* length of stack (head of th->stack) */
19
+ size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
20
+ #endif
21
+ VALUE *machine_stack;
22
+ VALUE *machine_stack_src;
23
+ #ifdef __ia64
24
+ VALUE *machine_register_stack;
25
+ VALUE *machine_register_stack_src;
26
+ int machine_register_stack_size;
27
+ #endif
28
+ rb_thread_t saved_thread;
29
+ rb_jmpbuf_t jmpbuf;
30
+ size_t machine_stack_size;
31
+ } rb_context_t;
32
+
33
+
34
+
35
+ enum fiber_status {
36
+ CREATED,
37
+ RUNNING,
38
+ TERMINATED
39
+ };
40
+
41
+ typedef struct rb_fiber_struct {
42
+ rb_context_t cont;
43
+ VALUE prev;
44
+ enum fiber_status status;
45
+ struct rb_fiber_struct *prev_fiber;
46
+ struct rb_fiber_struct *next_fiber;
47
+ } rb_fiber_t;
48
+
@@ -0,0 +1,192 @@
1
+ //extracted from ruby 1.9.2 p290, should be compatible with all 1.9.2's
2
+
3
+ //TODO: does conflict with ruby framework?
4
+ #include "ruby/re.h"
5
+
6
+ //FIXME: this should be autoextracted from ruby
7
+ // see how this is done in ruby-internal gem
8
+
9
+
10
+ #define MARK_STACK_MAX 1024
11
+
12
+ #ifndef CALC_EXACT_MALLOC_SIZE
13
+ #define CALC_EXACT_MALLOC_SIZE 0
14
+ #endif
15
+
16
+ typedef struct RVALUE {
17
+ union {
18
+ struct {
19
+ VALUE flags; /* always 0 for freed obj */
20
+ struct RVALUE *next;
21
+ } free;
22
+ struct RBasic basic;
23
+ struct RObject object;
24
+ struct RClass klass;
25
+ struct RFloat flonum;
26
+ struct RString string;
27
+ struct RArray array;
28
+ struct RRegexp regexp;
29
+ struct RHash hash;
30
+ struct RData data;
31
+ struct RTypedData typeddata;
32
+ struct RStruct rstruct;
33
+ struct RBignum bignum;
34
+ struct RFile file;
35
+ struct RNode node;
36
+ struct RMatch match;
37
+ struct RRational rational;
38
+ struct RComplex complex;
39
+ } as;
40
+ #ifdef GC_DEBUG
41
+ const char *file;
42
+ int line;
43
+ #endif
44
+ } RVALUE;
45
+
46
+ typedef struct gc_profile_record {
47
+ double gc_time;
48
+ double gc_mark_time;
49
+ double gc_sweep_time;
50
+ double gc_invoke_time;
51
+
52
+ size_t heap_use_slots;
53
+ size_t heap_live_objects;
54
+ size_t heap_free_objects;
55
+ size_t heap_total_objects;
56
+ size_t heap_use_size;
57
+ size_t heap_total_size;
58
+
59
+ int have_finalize;
60
+ int is_marked;
61
+
62
+ size_t allocate_increase;
63
+ size_t allocate_limit;
64
+ } gc_profile_record;
65
+
66
+ struct heaps_slot {
67
+ void *membase;
68
+ RVALUE *slot;
69
+ size_t limit;
70
+ uintptr_t *bits;
71
+ RVALUE *freelist;
72
+ struct heaps_slot *next;
73
+ struct heaps_slot *prev;
74
+ struct heaps_slot *free_next;
75
+ };
76
+
77
+ struct heaps_header {
78
+ struct heaps_slot *base;
79
+ uintptr_t *bits;
80
+ };
81
+
82
+ struct sorted_heaps_slot {
83
+ RVALUE *start;
84
+ RVALUE *end;
85
+ struct heaps_slot *slot;
86
+ };
87
+
88
+ struct heaps_free_bitmap {
89
+ struct heaps_free_bitmap *next;
90
+ };
91
+
92
+ struct gc_list {
93
+ VALUE *varptr;
94
+ struct gc_list *next;
95
+ };
96
+
97
+
98
+ // 1.9.2-p290:
99
+ typedef struct rb_objspace {
100
+ struct {
101
+ size_t limit;
102
+ size_t increase;
103
+ #if CALC_EXACT_MALLOC_SIZE
104
+ size_t allocated_size;
105
+ size_t allocations;
106
+ #endif
107
+ } malloc_params;
108
+ struct {
109
+ size_t increment;
110
+ struct heaps_slot *ptr;
111
+ size_t length;
112
+ size_t used;
113
+ RVALUE *freelist;
114
+ RVALUE *range[2];
115
+ RVALUE *freed;
116
+ } heap;
117
+ struct {
118
+ int dont_gc;
119
+ int during_gc;
120
+ } flags;
121
+ struct {
122
+ st_table *table;
123
+ RVALUE *deferred;
124
+ } final;
125
+ struct {
126
+ VALUE buffer[MARK_STACK_MAX];
127
+ VALUE *ptr;
128
+ int overflow;
129
+ } markstack;
130
+ struct {
131
+ int run;
132
+ gc_profile_record *record;
133
+ size_t count;
134
+ size_t size;
135
+ double invoke_time;
136
+ } profile;
137
+ struct gc_list *global_list;
138
+ unsigned int count;
139
+ int gc_stress;
140
+ } rb_objspace_t;
141
+
142
+ //
143
+ #define RANY(o) ((RVALUE*)(o))
144
+
145
+ #define malloc_limit objspace->malloc_params.limit
146
+ #define malloc_increase objspace->malloc_params.increase
147
+ #define heaps objspace->heap.ptr
148
+ #define heaps_length objspace->heap.length
149
+ #define heaps_used objspace->heap.used
150
+ #define lomem objspace->heap.range[0]
151
+ #define himem objspace->heap.range[1]
152
+ #define heaps_inc objspace->heap.increment
153
+ #define heaps_freed objspace->heap.freed
154
+ #define dont_gc objspace->flags.dont_gc
155
+ #define during_gc objspace->flags.during_gc
156
+ #define finalizing objspace->flags.finalizing
157
+ #define finalizer_table objspace->final.table
158
+ #define deferred_final_list objspace->final.deferred
159
+ #define mark_stack objspace->markstack.buffer
160
+ #define mark_stack_ptr objspace->markstack.ptr
161
+ #define mark_stack_overflow objspace->markstack.overflow
162
+ #define global_List objspace->global_list
163
+
164
+
165
+ //1.9.2-p290
166
+ static inline int
167
+ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
168
+ {
169
+ register RVALUE *p = RANY(ptr);
170
+ register struct heaps_slot *heap;
171
+ register size_t hi, lo, mid;
172
+
173
+ if (p < lomem || p > himem) return FALSE;
174
+ if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
175
+
176
+ /* check if p looks like a pointer using bsearch*/
177
+ lo = 0;
178
+ hi = heaps_used;
179
+ while (lo < hi) {
180
+ mid = (lo + hi) / 2;
181
+ heap = &heaps[mid];
182
+ if (heap->slot <= p) {
183
+ if (p < heap->slot + heap->limit)
184
+ return TRUE;
185
+ lo = mid + 1;
186
+ }
187
+ else {
188
+ hi = mid;
189
+ }
190
+ }
191
+ return FALSE;
192
+ }
@@ -0,0 +1,10 @@
1
+ //from 1.9.2
2
+ typedef enum {
3
+ CONST_PUBLIC = 0x00,
4
+ CONST_PRIVATE = 0x01
5
+ } rb_const_flag_t;
6
+
7
+ typedef struct rb_const_entry_struct {
8
+ rb_const_flag_t flag;
9
+ VALUE value; /* should be mark */
10
+ } rb_const_entry_t;
@@ -0,0 +1,45 @@
1
+ //FIXME: autogen this from ruby (this copied from 1.9.2p290)
2
+ struct thgroup {
3
+ int enclosed;
4
+ VALUE group;
5
+ };
6
+
7
+
8
+ //
9
+
10
+ struct enumerator {
11
+ VALUE obj;
12
+ ID meth;
13
+ VALUE args;
14
+ VALUE fib;
15
+ VALUE dst;
16
+ VALUE lookahead;
17
+ VALUE feedvalue;
18
+ VALUE stop_exc;
19
+ };
20
+
21
+ struct generator {
22
+ VALUE proc;
23
+ };
24
+
25
+ struct yielder {
26
+ VALUE proc;
27
+ };
28
+
29
+ //
30
+ struct METHOD {
31
+ VALUE recv;
32
+ VALUE rclass;
33
+ ID id;
34
+ rb_method_entry_t me;
35
+ };
36
+
37
+ //
38
+
39
+ #define METHOD_DEFINITIONP(m) m->me.def
40
+
41
+ #define HAVE_RB_CLASS_TBL 1
42
+ //class.c:
43
+ extern st_table *rb_class_tbl;
44
+
45
+ extern VALUE ruby_engine_name;
@@ -0,0 +1,53 @@
1
+ //1.9.3
2
+ //from cont.c:
3
+
4
+ #define CAPTURE_JUST_VALID_VM_STACK 1
5
+
6
+ enum context_type {
7
+ CONTINUATION_CONTEXT = 0,
8
+ FIBER_CONTEXT = 1,
9
+ ROOT_FIBER_CONTEXT = 2
10
+ };
11
+
12
+ typedef struct rb_context_struct {
13
+ enum context_type type;
14
+ VALUE self;
15
+ int argc;
16
+ VALUE value;
17
+ VALUE *vm_stack;
18
+ #ifdef CAPTURE_JUST_VALID_VM_STACK
19
+ size_t vm_stack_slen; /* length of stack (head of th->stack) */
20
+ size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
21
+ #endif
22
+ VALUE *machine_stack;
23
+ VALUE *machine_stack_src;
24
+ #ifdef __ia64
25
+ VALUE *machine_register_stack;
26
+ VALUE *machine_register_stack_src;
27
+ int machine_register_stack_size;
28
+ #endif
29
+ rb_thread_t saved_thread;
30
+ rb_jmpbuf_t jmpbuf;
31
+ size_t machine_stack_size;
32
+ } rb_context_t;
33
+
34
+ enum fiber_status {
35
+ CREATED,
36
+ RUNNING,
37
+ TERMINATED
38
+ };
39
+
40
+ typedef struct rb_fiber_struct {
41
+ rb_context_t cont;
42
+ VALUE prev;
43
+ enum fiber_status status;
44
+ struct rb_fiber_struct *prev_fiber;
45
+ struct rb_fiber_struct *next_fiber;
46
+ #if FIBER_USE_NATIVE
47
+ #ifdef _WIN32
48
+ void *fib_handle;
49
+ #else
50
+ ucontext_t context;
51
+ #endif
52
+ #endif
53
+ } rb_fiber_t;
@@ -0,0 +1,191 @@
1
+ //TODO: does conflict with ruby framework?
2
+ #include "ruby/re.h"
3
+
4
+ //gc.c
5
+
6
+ #define MARK_STACK_MAX 1024
7
+ //
8
+ /* for GC profile */
9
+ #define GC_PROFILE_MORE_DETAIL 0
10
+ typedef struct gc_profile_record {
11
+ double gc_time;
12
+ double gc_mark_time;
13
+ double gc_sweep_time;
14
+ double gc_invoke_time;
15
+
16
+ size_t heap_use_slots;
17
+ size_t heap_live_objects;
18
+ size_t heap_free_objects;
19
+ size_t heap_total_objects;
20
+ size_t heap_use_size;
21
+ size_t heap_total_size;
22
+
23
+ int have_finalize;
24
+ int is_marked;
25
+
26
+ size_t allocate_increase;
27
+ size_t allocate_limit;
28
+ } gc_profile_record;
29
+ //
30
+
31
+ typedef struct RVALUE {
32
+ union {
33
+ struct {
34
+ VALUE flags; /* always 0 for freed obj */
35
+ struct RVALUE *next;
36
+ } free;
37
+ struct RBasic basic;
38
+ struct RObject object;
39
+ struct RClass klass;
40
+ struct RFloat flonum;
41
+ struct RString string;
42
+ struct RArray array;
43
+ struct RRegexp regexp;
44
+ struct RHash hash;
45
+ struct RData data;
46
+ struct RTypedData typeddata;
47
+ struct RStruct rstruct;
48
+ struct RBignum bignum;
49
+ struct RFile file;
50
+ struct RNode node;
51
+ struct RMatch match;
52
+ struct RRational rational;
53
+ struct RComplex complex;
54
+ } as;
55
+ #ifdef GC_DEBUG
56
+ const char *file;
57
+ int line;
58
+ #endif
59
+ } RVALUE;
60
+
61
+ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
62
+ #pragma pack(pop)
63
+ #endif
64
+
65
+ struct heaps_slot {
66
+ void *membase;
67
+ RVALUE *slot;
68
+ size_t limit;
69
+ struct heaps_slot *next;
70
+ struct heaps_slot *prev;
71
+ };
72
+
73
+ struct sorted_heaps_slot {
74
+ RVALUE *start;
75
+ RVALUE *end;
76
+ struct heaps_slot *slot;
77
+ };
78
+
79
+ struct gc_list {
80
+ VALUE *varptr;
81
+ struct gc_list *next;
82
+ };
83
+
84
+ #define CALC_EXACT_MALLOC_SIZE 0
85
+
86
+ typedef struct rb_objspace {
87
+ struct {
88
+ size_t limit;
89
+ size_t increase;
90
+ #if CALC_EXACT_MALLOC_SIZE
91
+ size_t allocated_size;
92
+ size_t allocations;
93
+ #endif
94
+ } malloc_params;
95
+ struct {
96
+ size_t increment;
97
+ struct heaps_slot *ptr;
98
+ struct heaps_slot *sweep_slots;
99
+ struct sorted_heaps_slot *sorted;
100
+ size_t length;
101
+ size_t used;
102
+ RVALUE *freelist;
103
+ RVALUE *range[2];
104
+ RVALUE *freed;
105
+ size_t live_num;
106
+ size_t free_num;
107
+ size_t free_min;
108
+ size_t final_num;
109
+ size_t do_heap_free;
110
+ } heap;
111
+ struct {
112
+ int dont_gc;
113
+ int dont_lazy_sweep;
114
+ int during_gc;
115
+ } flags;
116
+ struct {
117
+ st_table *table;
118
+ RVALUE *deferred;
119
+ } final;
120
+ struct {
121
+ VALUE buffer[MARK_STACK_MAX];
122
+ VALUE *ptr;
123
+ int overflow;
124
+ } markstack;
125
+ struct {
126
+ int run;
127
+ gc_profile_record *record;
128
+ size_t count;
129
+ size_t size;
130
+ double invoke_time;
131
+ } profile;
132
+ struct gc_list *global_list;
133
+ size_t count;
134
+ int gc_stress;
135
+ } rb_objspace_t;
136
+
137
+ //
138
+
139
+ #define malloc_limit objspace->malloc_params.limit
140
+ #define malloc_increase objspace->malloc_params.increase
141
+ #define heaps objspace->heap.ptr
142
+ #define heaps_length objspace->heap.length
143
+ #define heaps_used objspace->heap.used
144
+ #define freelist objspace->heap.freelist
145
+ #define lomem objspace->heap.range[0]
146
+ #define himem objspace->heap.range[1]
147
+ #define heaps_inc objspace->heap.increment
148
+ #define heaps_freed objspace->heap.freed
149
+ #define dont_gc objspace->flags.dont_gc
150
+ #define during_gc objspace->flags.during_gc
151
+ #define finalizer_table objspace->final.table
152
+ #define deferred_final_list objspace->final.deferred
153
+ #define mark_stack objspace->markstack.buffer
154
+ #define mark_stack_ptr objspace->markstack.ptr
155
+ #define mark_stack_overflow objspace->markstack.overflow
156
+ #define global_List objspace->global_list
157
+ #define ruby_gc_stress objspace->gc_stress
158
+ #define initial_malloc_limit initial_params.initial_malloc_limit
159
+ #define initial_heap_min_slots initial_params.initial_heap_min_slots
160
+ #define initial_free_min initial_params.initial_free_min
161
+
162
+ //
163
+ #define RANY(o) ((RVALUE*)(o))
164
+ //
165
+ static inline int
166
+ is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)
167
+ {
168
+ register RVALUE *p = RANY(ptr);
169
+ register struct sorted_heaps_slot *heap;
170
+ register size_t hi, lo, mid;
171
+
172
+ if (p < lomem || p > himem) return FALSE;
173
+ if ((VALUE)p % sizeof(RVALUE) != 0) return FALSE;
174
+
175
+ /* check if p looks like a pointer using bsearch*/
176
+ lo = 0;
177
+ hi = heaps_used;
178
+ while (lo < hi) {
179
+ mid = (lo + hi) / 2;
180
+ heap = &objspace->heap.sorted[mid];
181
+ if (heap->start <= p) {
182
+ if (p < heap->end)
183
+ return TRUE;
184
+ lo = mid + 1;
185
+ }
186
+ else {
187
+ hi = mid;
188
+ }
189
+ }
190
+ return FALSE;
191
+ }
@@ -0,0 +1,51 @@
1
+ //FIXME: autogen this from ruby (this copied from 1.9.3p194)
2
+
3
+ // thread.c:
4
+ struct thgroup {
5
+ int enclosed;
6
+ VALUE group;
7
+ };
8
+
9
+ // enumerator.c:
10
+ struct enumerator {
11
+ VALUE obj;
12
+ ID meth;
13
+ VALUE args;
14
+ VALUE fib;
15
+ VALUE dst;
16
+ VALUE lookahead;
17
+ VALUE feedvalue;
18
+ VALUE stop_exc;
19
+ };
20
+
21
+ //
22
+ struct generator {
23
+ VALUE proc;
24
+ };
25
+
26
+ struct yielder {
27
+ VALUE proc;
28
+ };
29
+
30
+
31
+ // proc.c:
32
+ struct METHOD {
33
+ VALUE recv;
34
+ VALUE rclass;
35
+ ID id;
36
+ rb_method_entry_t *me;
37
+ struct unlinked_method_entry_list_entry *ume;
38
+ };
39
+
40
+ //
41
+ #define METHOD_DEFINITIONP(m) (m->me ? m->me->def : NULL)
42
+
43
+ //class.c:
44
+ // #define HAVE_RB_CLASS_TBL 1
45
+ //For som reason this fails to link on 1.9.3 :(
46
+ // extern st_table *rb_class_tbl;
47
+
48
+ #define ruby_current_thread ((rb_thread_t *)RTYPEDDATA_DATA(rb_thread_current()))
49
+
50
+ //FIXME: get global const for it: rb_define_global_const("RUBY_ENGINE", ruby_engine_name = MKSTR(engine));
51
+ #define ruby_engine_name Qnil
data/heap_dump.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = HeapDump::VERSION
17
17
 
18
- gem.required_ruby_version = '~>1.9.2p290' # heap structure changed in 1.9.3, support later
18
+ gem.required_ruby_version = '~>1.9.2'
19
19
  #gem.platform = Gem::Platform::CURRENT # other than osx - maybe later
20
20
 
21
21
  gem.extensions = "ext/heap_dump/extconf.rb"
@@ -1,3 +1,3 @@
1
1
  module HeapDump
2
- VERSION = "0.0.25"
2
+ VERSION = "0.0.26"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heap_dump
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.25
4
+ version: 0.0.26
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-01 00:00:00.000000000 Z
12
+ date: 2012-10-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debugger-ruby_core_source
@@ -75,6 +75,13 @@ files:
75
75
  - ext/heap_dump/extconf.rb
76
76
  - ext/heap_dump/heap_dump.c
77
77
  - ext/heap_dump/ruby_io.h
78
+ - ext/heap_dump/specific/ruby-1.9.2/fiber.h
79
+ - ext/heap_dump/specific/ruby-1.9.2/gc_internal.h
80
+ - ext/heap_dump/specific/ruby-1.9.2/internal_constant.h
81
+ - ext/heap_dump/specific/ruby-1.9.2/internal_typed_data.h
82
+ - ext/heap_dump/specific/ruby-1.9.3/fiber.h
83
+ - ext/heap_dump/specific/ruby-1.9.3/gc_internal.h
84
+ - ext/heap_dump/specific/ruby-1.9.3/internal_typed_data.h
78
85
  - heap_dump.gemspec
79
86
  - lib/heap_dump.rb
80
87
  - lib/heap_dump/version.rb
@@ -89,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
96
  requirements:
90
97
  - - ~>
91
98
  - !ruby/object:Gem::Version
92
- version: 1.9.2p290
99
+ version: 1.9.2
93
100
  required_rubygems_version: !ruby/object:Gem::Requirement
94
101
  none: false
95
102
  requirements:
@@ -98,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
105
  version: '0'
99
106
  segments:
100
107
  - 0
101
- hash: -3428409175290370269
108
+ hash: -4211610270399320096
102
109
  requirements: []
103
110
  rubyforge_project:
104
111
  rubygems_version: 1.8.24