Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
objspace_dump.c
Go to the documentation of this file.
1/**********************************************************************
2
3 objspace_dump.c - Heap dumping ObjectSpace extender for MRI.
4
5 $Author$
6 created at: Sat Oct 11 10:11:00 2013
7
8 NOTE: This extension library is not expected to exist except C Ruby.
9
10 All the files in this distribution are covered under the Ruby's
11 license (see the file COPYING).
12
13**********************************************************************/
14
15#include "gc.h"
16#include "internal.h"
17#include "internal/hash.h"
18#include "internal/string.h"
19#include "internal/sanitizers.h"
20#include "node.h"
21#include "objspace.h"
22#include "ruby/debug.h"
23#include "ruby/util.h"
24#include "ruby/io.h"
25#include "vm_core.h"
26
27RUBY_EXTERN const char ruby_hexdigits[];
28
29#define BUFFER_CAPACITY 4096
30
35 const char *root_category;
39 unsigned int roots: 1;
40 unsigned int full_heap: 1;
41 unsigned int partial_dump;
42 size_t since;
43 unsigned long buffer_len;
45};
46
47static void
48dump_flush(struct dump_config *dc)
49{
50 if (dc->buffer_len) {
51 if (dc->stream) {
52 size_t written = rb_io_bufwrite(dc->stream, dc->buffer, dc->buffer_len);
53 if (written < dc->buffer_len) {
54 MEMMOVE(dc->buffer, dc->buffer + written, char, dc->buffer_len - written);
55 dc->buffer_len -= written;
56 return;
57 }
58 }
59 else if (dc->string) {
60 rb_str_cat(dc->string, dc->buffer, dc->buffer_len);
61 }
62 dc->buffer_len = 0;
63 }
64}
65
66static inline void
67buffer_ensure_capa(struct dump_config *dc, unsigned long requested)
68{
69 RUBY_ASSERT(requested <= BUFFER_CAPACITY);
70 if (requested + dc->buffer_len >= BUFFER_CAPACITY) {
71 dump_flush(dc);
72 if (requested + dc->buffer_len >= BUFFER_CAPACITY) {
73 rb_raise(rb_eIOError, "full buffer");
74 }
75 }
76}
77
78static void buffer_append(struct dump_config *dc, const char *cstr, unsigned long len)
79{
80 if (LIKELY(len > 0)) {
81 buffer_ensure_capa(dc, len);
82 MEMCPY(dc->buffer + dc->buffer_len, cstr, char, len);
83 dc->buffer_len += len;
84 }
85}
86
87# define dump_append(dc, str) buffer_append(dc, (str), (long)strlen(str))
88
89static void
90dump_append_ld(struct dump_config *dc, const long number)
91{
92 const int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT - 1) + 2;
93 buffer_ensure_capa(dc, width);
94 unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%ld", number);
95 RUBY_ASSERT(required <= width);
96 dc->buffer_len += required;
97}
98
99static void
100dump_append_lu(struct dump_config *dc, const unsigned long number)
101{
102 const int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT) + 1;
103 buffer_ensure_capa(dc, width);
104 unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%lu", number);
105 RUBY_ASSERT(required <= width);
106 dc->buffer_len += required;
107}
108
109static void
110dump_append_g(struct dump_config *dc, const double number)
111{
112 unsigned long capa_left = BUFFER_CAPACITY - dc->buffer_len;
113 unsigned long required = snprintf(dc->buffer + dc->buffer_len, capa_left, "%#g", number);
114
115 if (required >= capa_left) {
116 buffer_ensure_capa(dc, required);
117 capa_left = BUFFER_CAPACITY - dc->buffer_len;
118 snprintf(dc->buffer + dc->buffer_len, capa_left, "%#g", number);
119 }
120 dc->buffer_len += required;
121}
122
123static void
124dump_append_d(struct dump_config *dc, const int number)
125{
126 const int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT - 1) + 2;
127 buffer_ensure_capa(dc, width);
128 unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%d", number);
129 RUBY_ASSERT(required <= width);
130 dc->buffer_len += required;
131}
132
133static void
134dump_append_sizet(struct dump_config *dc, const size_t number)
135{
136 const int width = DECIMAL_SIZE_OF_BITS(sizeof(number) * CHAR_BIT) + 1;
137 buffer_ensure_capa(dc, width);
138 unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "%"PRIuSIZE, number);
139 RUBY_ASSERT(required <= width);
140 dc->buffer_len += required;
141}
142
143static void
144dump_append_c(struct dump_config *dc, char c)
145{
146 if (c <= 0x1f) {
147 const int width = (sizeof(c) * CHAR_BIT / 4) + 5;
148 buffer_ensure_capa(dc, width);
149 unsigned long required = snprintf(dc->buffer + dc->buffer_len, width, "\\u00%02x", c);
150 RUBY_ASSERT(required <= width);
151 dc->buffer_len += required;
152 }
153 else {
154 buffer_ensure_capa(dc, 1);
155 dc->buffer[dc->buffer_len] = c;
156 dc->buffer_len++;
157 }
158}
159
160static void
161dump_append_ref(struct dump_config *dc, VALUE ref)
162{
163 RUBY_ASSERT(ref > 0);
164
165 char buffer[((sizeof(VALUE) * CHAR_BIT + 3) / 4) + 4];
166 char *buffer_start, *buffer_end;
167
168 buffer_start = buffer_end = &buffer[sizeof(buffer)];
169 *--buffer_start = '"';
170 while (ref) {
171 *--buffer_start = ruby_hexdigits[ref & 0xF];
172 ref >>= 4;
173 }
174 *--buffer_start = 'x';
175 *--buffer_start = '0';
176 *--buffer_start = '"';
177 buffer_append(dc, buffer_start, buffer_end - buffer_start);
178}
179
180static void
181dump_append_string_value(struct dump_config *dc, VALUE obj)
182{
183 long i;
184 char c;
185 const char *value;
186
187 dump_append(dc, "\"");
188 for (i = 0, value = RSTRING_PTR(obj); i < RSTRING_LEN(obj); i++) {
189 switch ((c = value[i])) {
190 case '\\':
191 dump_append(dc, "\\\\");
192 break;
193 case '"':
194 dump_append(dc, "\\\"");
195 break;
196 case '\0':
197 dump_append(dc, "\\u0000");
198 break;
199 case '\b':
200 dump_append(dc, "\\b");
201 break;
202 case '\t':
203 dump_append(dc, "\\t");
204 break;
205 case '\f':
206 dump_append(dc, "\\f");
207 break;
208 case '\n':
209 dump_append(dc, "\\n");
210 break;
211 case '\r':
212 dump_append(dc, "\\r");
213 break;
214 case '\177':
215 dump_append(dc, "\\u007f");
216 break;
217 default:
218 dump_append_c(dc, c);
219 }
220 }
221 dump_append(dc, "\"");
222}
223
224static void
225dump_append_symbol_value(struct dump_config *dc, VALUE obj)
226{
227 dump_append(dc, "{\"type\":\"SYMBOL\", \"value\":");
228 dump_append_string_value(dc, rb_sym2str(obj));
229 dump_append(dc, "}");
230}
231
232static inline const char *
233obj_type(VALUE obj)
234{
235 switch (BUILTIN_TYPE(obj)) {
236#define CASE_TYPE(type) case T_##type: return #type
237 CASE_TYPE(NONE);
238 CASE_TYPE(NIL);
239 CASE_TYPE(OBJECT);
240 CASE_TYPE(CLASS);
241 CASE_TYPE(ICLASS);
242 CASE_TYPE(MODULE);
243 CASE_TYPE(FLOAT);
244 CASE_TYPE(STRING);
245 CASE_TYPE(REGEXP);
246 CASE_TYPE(ARRAY);
247 CASE_TYPE(HASH);
248 CASE_TYPE(STRUCT);
249 CASE_TYPE(BIGNUM);
251 CASE_TYPE(FIXNUM);
254 CASE_TYPE(DATA);
256 CASE_TYPE(SYMBOL);
257 CASE_TYPE(RATIONAL);
258 CASE_TYPE(COMPLEX);
259 CASE_TYPE(IMEMO);
262 CASE_TYPE(ZOMBIE);
263#undef CASE_TYPE
264 default: break;
265 }
266 return "UNKNOWN";
267}
268
269static void
270dump_append_special_const(struct dump_config *dc, VALUE value)
271{
272 if (value == Qtrue) {
273 dump_append(dc, "true");
274 }
275 else if (value == Qfalse) {
276 dump_append(dc, "false");
277 }
278 else if (value == Qnil) {
279 dump_append(dc, "null");
280 }
281 else if (FIXNUM_P(value)) {
282 dump_append_ld(dc, FIX2LONG(value));
283 }
284 else if (FLONUM_P(value)) {
285 dump_append_g(dc, RFLOAT_VALUE(value));
286 }
287 else if (SYMBOL_P(value)) {
288 dump_append_symbol_value(dc, value);
289 }
290 else {
291 dump_append(dc, "{}");
292 }
293}
294
295static void
296reachable_object_i(VALUE ref, void *data)
297{
298 struct dump_config *dc = (struct dump_config *)data;
299
300 if (dc->cur_obj_klass == ref)
301 return;
302
303 if (dc->cur_obj_references == 0) {
304 dump_append(dc, ", \"references\":[");
305 dump_append_ref(dc, ref);
306 }
307 else {
308 dump_append(dc, ", ");
309 dump_append_ref(dc, ref);
310 }
311
312 dc->cur_obj_references++;
313}
314
315static void
316dump_append_string_content(struct dump_config *dc, VALUE obj)
317{
318 dump_append(dc, ", \"bytesize\":");
319 dump_append_ld(dc, RSTRING_LEN(obj));
320 if (!STR_EMBED_P(obj) && !STR_SHARED_P(obj) && (long)rb_str_capacity(obj) != RSTRING_LEN(obj)) {
321 dump_append(dc, ", \"capacity\":");
322 dump_append_sizet(dc, rb_str_capacity(obj));
323 }
324
325 if (is_ascii_string(obj)) {
326 dump_append(dc, ", \"value\":");
327 dump_append_string_value(dc, obj);
328 }
329}
330
331static void
332dump_object(VALUE obj, struct dump_config *dc)
333{
334 size_t memsize;
336 rb_io_t *fptr;
338 size_t n, i;
339
340 if (SPECIAL_CONST_P(obj)) {
341 dump_append_special_const(dc, obj);
342 return;
343 }
344
345 dc->cur_obj = obj;
346 dc->cur_obj_references = 0;
347 dc->cur_obj_klass = BUILTIN_TYPE(obj) == T_NODE ? 0 : RBASIC_CLASS(obj);
348
349 if (dc->partial_dump && (!ainfo || ainfo->generation < dc->since)) {
350 return;
351 }
352
353 if (dc->cur_obj == dc->string)
354 return;
355
356 dump_append(dc, "{\"address\":");
357 dump_append_ref(dc, obj);
358
359 dump_append(dc, ", \"type\":\"");
360 dump_append(dc, obj_type(obj));
361 dump_append(dc, "\"");
362
363 if (dc->cur_obj_klass) {
364 dump_append(dc, ", \"class\":");
365 dump_append_ref(dc, dc->cur_obj_klass);
366 }
367 if (rb_obj_frozen_p(obj))
368 dump_append(dc, ", \"frozen\":true");
369
370 switch (BUILTIN_TYPE(obj)) {
371 case T_NONE:
372 dump_append(dc, "}\n");
373 return;
374
375 case T_IMEMO:
376 dump_append(dc, ", \"imemo_type\":\"");
378 dump_append(dc, "\"");
379 break;
380
381 case T_SYMBOL:
382 dump_append_string_content(dc, rb_sym2str(obj));
383 break;
384
385 case T_STRING:
386 if (STR_EMBED_P(obj))
387 dump_append(dc, ", \"embedded\":true");
388 if (is_broken_string(obj))
389 dump_append(dc, ", \"broken\":true");
390 if (FL_TEST(obj, RSTRING_FSTR))
391 dump_append(dc, ", \"fstring\":true");
392 if (STR_SHARED_P(obj))
393 dump_append(dc, ", \"shared\":true");
394 else
395 dump_append_string_content(dc, obj);
396
397 if (!ENCODING_IS_ASCII8BIT(obj)) {
398 dump_append(dc, ", \"encoding\":\"");
400 dump_append(dc, "\"");
401 }
402 break;
403
404 case T_HASH:
405 dump_append(dc, ", \"size\":");
406 dump_append_sizet(dc, (size_t)RHASH_SIZE(obj));
407 if (FL_TEST(obj, RHASH_PROC_DEFAULT)) {
408 dump_append(dc, ", \"default\":");
409 dump_append_ref(dc, RHASH_IFNONE(obj));
410 }
411 break;
412
413 case T_ARRAY:
414 dump_append(dc, ", \"length\":");
415 dump_append_ld(dc, RARRAY_LEN(obj));
416 if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, ELTS_SHARED))
417 dump_append(dc, ", \"shared\":true");
418 if (RARRAY_LEN(obj) > 0 && FL_TEST(obj, RARRAY_EMBED_FLAG))
419 dump_append(dc, ", \"embedded\":true");
420 break;
421
422 case T_CLASS:
423 case T_MODULE:
424 if (dc->cur_obj_klass) {
425 VALUE mod_name = rb_mod_name(obj);
426 if (!NIL_P(mod_name)) {
427 dump_append(dc, ", \"name\":\"");
428 dump_append(dc, RSTRING_PTR(mod_name));
429 dump_append(dc, "\"");
430 }
431 }
432 break;
433
434 case T_DATA:
435 if (RTYPEDDATA_P(obj)) {
436 dump_append(dc, ", \"struct\":\"");
437 dump_append(dc, RTYPEDDATA_TYPE(obj)->wrap_struct_name);
438 dump_append(dc, "\"");
439 }
440 break;
441
442 case T_FLOAT:
443 dump_append(dc, ", \"value\":\"");
444 dump_append_g(dc, RFLOAT_VALUE(obj));
445 dump_append(dc, "\"");
446 break;
447
448 case T_OBJECT:
449 dump_append(dc, ", \"ivars\":");
450 dump_append_lu(dc, ROBJECT_NUMIV(obj));
451 break;
452
453 case T_FILE:
454 fptr = RFILE(obj)->fptr;
455 if (fptr) {
456 dump_append(dc, ", \"fd\":");
457 dump_append_d(dc, fptr->fd);
458 }
459 break;
460
461 case T_ZOMBIE:
462 dump_append(dc, "}\n");
463 return;
464
465 default:
466 break;
467 }
468
469 rb_objspace_reachable_objects_from(obj, reachable_object_i, dc);
470 if (dc->cur_obj_references > 0)
471 dump_append(dc, "]");
472
473 if (ainfo) {
474 if (ainfo->path) {
475 dump_append(dc, ", \"file\":\"");
476 dump_append(dc, ainfo->path);
477 dump_append(dc, "\"");
478 }
479 if (ainfo->line) {
480 dump_append(dc, ", \"line\":");
481 dump_append_lu(dc, ainfo->line);
482 }
483 if (RTEST(ainfo->mid)) {
484 VALUE m = rb_sym2str(ainfo->mid);
485 dump_append(dc, ", \"method\":");
486 dump_append_string_value(dc, m);
487 }
488 dump_append(dc, ", \"generation\":");
489 dump_append_sizet(dc, ainfo->generation);
490 }
491
492 if ((memsize = rb_obj_memsize_of(obj)) > 0) {
493 dump_append(dc, ", \"memsize\":");
494 dump_append_sizet(dc, memsize);
495 }
496
497 if ((n = rb_obj_gc_flags(obj, flags, sizeof(flags))) > 0) {
498 dump_append(dc, ", \"flags\":{");
499 for (i=0; i<n; i++) {
500 dump_append(dc, "\"");
502 dump_append(dc, "\":true");
503 if (i != n-1) dump_append(dc, ", ");
504 }
505 dump_append(dc, "}");
506 }
507
508 dump_append(dc, "}\n");
509}
510
511static int
512heap_i(void *vstart, void *vend, size_t stride, void *data)
513{
514 struct dump_config *dc = (struct dump_config *)data;
515 VALUE v = (VALUE)vstart;
516 for (; v != (VALUE)vend; v += stride) {
517 void *ptr = asan_poisoned_object_p(v);
518 asan_unpoison_object(v, false);
519
520 if (dc->full_heap || RBASIC(v)->flags)
521 dump_object(v, dc);
522
523 if (ptr) {
524 asan_poison_object(v);
525 }
526 }
527 return 0;
528}
529
530static void
531root_obj_i(const char *category, VALUE obj, void *data)
532{
533 struct dump_config *dc = (struct dump_config *)data;
534
535 if (dc->root_category != NULL && category != dc->root_category)
536 dump_append(dc, "]}\n");
537 if (dc->root_category == NULL || category != dc->root_category) {
538 dump_append(dc, "{\"type\":\"ROOT\", \"root\":\"");
539 dump_append(dc, category);
540 dump_append(dc, "\", \"references\":[");
541 dump_append_ref(dc, obj);
542 }
543 else {
544 dump_append(dc, ", ");
545 dump_append_ref(dc, obj);
546 }
547
548 dc->root_category = category;
549 dc->roots = 1;
550}
551
552static void
553dump_output(struct dump_config *dc, VALUE output, VALUE full, VALUE since)
554{
555
556 dc->full_heap = 0;
557 dc->buffer_len = 0;
558
559 if (TYPE(output) == T_STRING) {
560 dc->stream = Qfalse;
561 dc->string = output;
562 } else {
563 dc->stream = output;
564 dc->string = Qfalse;
565 }
566
567 if (full == Qtrue) {
568 dc->full_heap = 1;
569 }
570
571 if (RTEST(since)) {
572 dc->partial_dump = 1;
573 dc->since = NUM2SIZET(since);
574 } else {
575 dc->partial_dump = 0;
576 }
577}
578
579static VALUE
580dump_result(struct dump_config *dc)
581{
582 dump_flush(dc);
583
584 if (dc->string) {
585 return dc->string;
586 } else {
587 rb_io_flush(dc->stream);
588 return dc->stream;
589 }
590}
591
592static VALUE
593objspace_dump(VALUE os, VALUE obj, VALUE output)
594{
595 struct dump_config dc = {0,};
596 dump_output(&dc, output, Qnil, Qnil);
597
598 dump_object(obj, &dc);
599
600 return dump_result(&dc);
601}
602
603static VALUE
604objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since)
605{
606 struct dump_config dc = {0,};
607 dump_output(&dc, output, full, since);
608
609 if (!dc.partial_dump || dc.since == 0) {
610 /* dump roots */
612 if (dc.roots) dump_append(&dc, "]}\n");
613 }
614
615 /* dump all objects */
616 rb_objspace_each_objects(heap_i, &dc);
617
618 return dump_result(&dc);
619}
620
621void
623{
624#undef rb_intern
625#if 0
626 rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */
627#endif
628
629 rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2);
630 rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 3);
631
632 /* force create static IDs */
633 rb_obj_gc_flags(rb_mObjSpace, 0, 0);
634}
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy iff RUBY_DEBUG is truthy.
Definition: assert.h:177
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
Definition: cxxanyargs.hpp:672
struct RIMemo * ptr
Definition: debug.c:88
#define RUBY_EXTERN
Definition: dllexport.h:36
#define RFLOAT_VALUE
Definition: double.h:28
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:414
#define MATCH(s)
uint8_t len
Definition: escape.c:17
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define LIKELY(x)
Definition: ffi_common.h:125
#define ELTS_SHARED
Definition: fl_type.h:84
size_t rb_obj_memsize_of(VALUE obj)
Definition: gc.c:4296
void rb_objspace_reachable_objects_from(VALUE obj, void(func)(VALUE, void *), void *data)
Definition: gc.c:10169
const char * rb_imemo_name(enum imemo_type type)
Definition: gc.c:2385
void rb_objspace_each_objects(each_obj_callback *callback, void *data)
Definition: gc.c:3285
void rb_objspace_reachable_objects_from_root(void(func)(const char *category, VALUE, void *), void *passing_data)
Definition: gc.c:10202
size_t rb_obj_gc_flags(VALUE obj, ID *flags, size_t max)
Definition: gc.c:7908
VALUE rb_eIOError
Definition: io.c:185
VALUE rb_define_module(const char *name)
Definition: class.c:871
#define FL_TEST
Definition: fl_type.h:130
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
VALUE rb_obj_frozen_p(VALUE)
Definition: object.c:1113
imemo_type
Definition: imemo.h:34
#define rb_enc_name(enc)
Definition: encoding.h:168
#define ENCODING_GET(obj)
Definition: encoding.h:51
#define ENCODING_IS_ASCII8BIT(obj)
Definition: encoding.h:52
VALUE rb_io_flush(VALUE)
Definition: io.c:2052
VALUE rb_str_cat(VALUE, const char *, long)
Definition: string.c:2962
size_t rb_str_capacity(VALUE)
Definition: string.c:773
VALUE rb_mod_name(VALUE)
Definition: variable.c:118
const char * rb_id2name(ID)
Definition: symbol.c:944
VALUE rb_sym2str(VALUE)
Definition: symbol.c:927
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Definition: io.c:1698
#define DECIMAL_SIZE_OF_BITS(n)
Definition: util.h:19
Internal header for GC.
#define RB_OBJ_GC_FLAGS_MAX
Definition: gc.h:40
Internal header for Hash.
@ RHASH_PROC_DEFAULT
Definition: hash.h:25
Internal header for String.
#define PRIuSIZE
Definition: inttypes.h:127
#define CHAR_BIT
Definition: limits.h:44
#define FIX2LONG
Definition: long.h:46
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
#define MEMMOVE(p1, p2, type, n)
Definition: memory.h:130
#define TRUE
Definition: nkf.h:175
#define FALSE
Definition: nkf.h:174
struct allocation_info * objspace_lookup_allocation_info(VALUE obj)
#define CASE_TYPE(type)
void Init_objspace_dump(VALUE rb_mObjSpace)
#define BUFFER_CAPACITY
Definition: objspace_dump.c:29
#define dump_append(dc, str)
Definition: objspace_dump.c:87
const char ruby_hexdigits[]
Definition: util.c:34
#define NIL
Definition: puff.h:29
#define RARRAY_EMBED_FLAG
Definition: rarray.h:43
#define RARRAY_LEN
Definition: rarray.h:52
#define RBASIC(obj)
Definition: rbasic.h:34
#define RBASIC_CLASS
Definition: rbasic.h:35
#define NULL
Definition: regenc.h:69
#define RFILE(obj)
Definition: rfile.h:35
#define RHASH_IFNONE(h)
Definition: rhash.h:49
#define RHASH_SIZE(h)
Definition: rhash.h:50
#define RSTRING_FSTR
Definition: rstring.h:40
Internal header for ASAN / MSAN / etc.
#define NUM2SIZET
Definition: size_t.h:51
#define SPECIAL_CONST_P
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
#define FIXNUM_P
Definition: node.h:149
VALUE flags
Definition: objspace.h:8
unsigned long line
Definition: objspace.h:13
const char * path
Definition: objspace.h:12
size_t generation
Definition: objspace.h:16
unsigned int roots
Definition: objspace_dump.c:39
size_t cur_obj_references
Definition: objspace_dump.c:38
unsigned int full_heap
Definition: objspace_dump.c:40
size_t since
Definition: objspace_dump.c:42
char buffer[BUFFER_CAPACITY]
Definition: objspace_dump.c:44
VALUE cur_obj_klass
Definition: objspace_dump.c:37
unsigned int partial_dump
Definition: objspace_dump.c:41
const char * root_category
Definition: objspace_dump.c:35
unsigned long buffer_len
Definition: objspace_dump.c:43
Definition: io.h:61
int fd
Definition: io.h:65
#define snprintf
Definition: subst.h:14
#define UNDEF
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define TYPE(_)
Definition: value_type.h:105
#define T_FILE
Definition: value_type.h:61
#define T_STRING
Definition: value_type.h:77
#define T_FLOAT
Definition: value_type.h:63
#define T_IMEMO
Definition: value_type.h:66
#define T_DATA
Definition: value_type.h:59
#define T_NONE
Definition: value_type.h:73
#define T_NODE
Definition: value_type.h:72
#define T_MODULE
Definition: value_type.h:69
#define T_HASH
Definition: value_type.h:64
#define T_ZOMBIE
Definition: value_type.h:82
#define T_ARRAY
Definition: value_type.h:55
#define T_OBJECT
Definition: value_type.h:74
#define T_SYMBOL
Definition: value_type.h:79
#define T_CLASS
Definition: value_type.h:57
#define BUILTIN_TYPE
Definition: value_type.h:84
#define SYMBOL_P
Definition: value_type.h:87