heap_dump 0.0.25 → 0.0.26

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