void *base;
GC_print_heap_obj(GC_base(current));
- GC_err_printf("\n");
+
for (i = 0; ; ++i) {
source = GC_get_back_ptr_info(current, &base, &offset);
if (GC_UNREFERENCED == source) {
GC_err_printf("offset %ld in object:\n", (long)offset);
/* Take GC_base(base) to get real base, i.e. header. */
GC_print_heap_obj(GC_base(base));
- GC_err_printf("\n");
break;
default:
GC_err_printf("INTERNAL ERROR: UNEXPECTED SOURCE!!!!\n");
GC_describe_type_fns[kind] = fn;
}
-/* Print a type description for the object whose client-visible address */
-/* is p. */
-STATIC void GC_print_type(ptr_t p)
+#define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
+
+#ifndef SHORT_DBG_HDRS
+# define IF_NOT_SHORTDBG_HDRS(x) x
+# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* comma */, x
+#else
+# define IF_NOT_SHORTDBG_HDRS(x) /* empty */
+# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* empty */
+#endif
+
+/* Print a human-readable description of the object to stderr. */
+/* p points to somewhere inside an object with the debugging info. */
+STATIC void GC_print_obj(ptr_t p)
{
- hdr * hhdr = GC_find_header(p);
- char buffer[GC_TYPE_DESCR_LEN + 1];
- int kind = hhdr -> hb_obj_kind;
+ oh * ohdr = (oh *)GC_base(p);
+ ptr_t q;
+ hdr * hhdr;
+ int kind;
char *kind_str;
+ char buffer[GC_TYPE_DESCR_LEN + 1];
+
+ GC_ASSERT(I_DONT_HOLD_LOCK());
+# ifdef LINT2
+ if (!ohdr) ABORT("Invalid GC_print_obj argument");
+# endif
- if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
+ q = (ptr_t)(ohdr + 1);
+ /* Print a type description for the object whose client-visible */
+ /* address is q. */
+ hhdr = GC_find_header(q);
+ kind = hhdr -> hb_obj_kind;
+ if (0 != GC_describe_type_fns[kind] && GC_is_marked(ohdr)) {
/* This should preclude free list objects except with */
/* thread-local allocation. */
buffer[GC_TYPE_DESCR_LEN] = 0;
- (GC_describe_type_fns[kind])(p, buffer);
+ (GC_describe_type_fns[kind])(q, buffer);
GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
kind_str = buffer;
} else {
break;
# ifdef ATOMIC_UNCOLLECTABLE
case AUNCOLLECTABLE:
- kind_str = "ATOMIC UNCOLLECTABLE";
+ kind_str = "ATOMIC_UNCOLLECTABLE";
break;
# endif
case STUBBORN:
break;
default:
kind_str = NULL;
+ /* The alternative is to use snprintf(buffer) but it is */
+ /* not quite portable (see vsnprintf in misc.c). */
}
}
+
if (NULL != kind_str) {
- GC_err_puts(kind_str);
+ GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,") " %s)\n",
+ (ptr_t)ohdr + sizeof(oh),
+ ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
+ COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
+ kind_str);
} else {
- GC_err_printf("kind=%d descr=0x%lx",
+ GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,")
+ " kind=%d descr=0x%lx)\n", (ptr_t)ohdr + sizeof(oh),
+ ohdr->oh_string, GET_OH_LINENUM(ohdr) /*, */
+ COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz),
kind, (unsigned long)hhdr->hb_descr);
}
-}
-
-#define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
-
-#ifndef SHORT_DBG_HDRS
-# define IF_NOT_SHORTDBG_HDRS(x) x
-# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* comma */, x
-#else
-# define IF_NOT_SHORTDBG_HDRS(x) /* empty */
-# define COMMA_IFNOT_SHORTDBG_HDRS(x) /* empty */
-#endif
-
-/* Print a human-readable description of the object to stderr. p points */
-/* to somewhere inside an object with the debugging info. */
-STATIC void GC_print_obj(ptr_t p)
-{
- oh * ohdr = (oh *)GC_base(p);
-
- GC_ASSERT(I_DONT_HOLD_LOCK());
-# ifdef LINT2
- if (!ohdr) ABORT("Invalid GC_print_obj argument");
-# endif
- GC_err_printf("%p (%s:%d," IF_NOT_SHORTDBG_HDRS(" sz=%lu,") " ",
- (ptr_t)ohdr + sizeof(oh), ohdr->oh_string,
- GET_OH_LINENUM(ohdr) /*, */
- COMMA_IFNOT_SHORTDBG_HDRS((unsigned long)ohdr->oh_sz));
- GC_print_type((ptr_t)(ohdr + 1));
- GC_err_puts(")\n");
PRINT_CALL_CHAIN(ohdr);
}
GC_ASSERT(I_DONT_HOLD_LOCK());
if (GC_n_smashed == 0) return;
- GC_err_printf("GC_check_heap_block: found smashed heap objects:\n");
+ GC_err_printf("GC_check_heap_block: found %u smashed heap objects:\n",
+ GC_n_smashed);
for (i = 0; i < GC_n_smashed; ++i) {
ptr_t base = (ptr_t)GC_base(GC_smashed[i]);
GC_smashed[i] = 0;
}
GC_n_smashed = 0;
- GC_err_printf("\n");
}
/* Check all marked objects in the given block for validity */
/* Print GC_smashed if it's not empty. */
/* Clear GC_smashed list. */
GC_EXTERN void (*GC_print_heap_obj)(ptr_t p);
- /* If possible print s followed by a more */
- /* detailed description of the object */
- /* referred to by p. */
+ /* If possible print (using GC_err_printf) */
+ /* a more detailed description (terminated with */
+ /* "\n") of the object referred to by p. */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
void GC_print_address_map(void);
/* Logging and diagnostic output: */
/* GC_printf is used typically on client explicit print requests. */
+/* It's recommended to put "\n" at 'format' string end (for atomicity). */
GC_API_PRIV void GC_printf(const char * format, ...)
GC_ATTR_FORMAT_PRINTF(1, 2);
/* A version of printf that doesn't allocate, */