Plug up leaky abstraction that (%INSTANCE-REF struct 0) is a LAYOUT.
[sbcl.git] / src / runtime / print.c
blob7fcd88494952a14481665f373ac421824b342f1e
1 /* code for low-level debugging/diagnostic output */
3 /*
4 * This software is part of the SBCL system. See the README file for
5 * more information.
7 * This software is derived from the CMU CL system, which was
8 * written at Carnegie Mellon University and released into the
9 * public domain. The software is in the public domain and is
10 * provided with absolutely no warranty. See the COPYING and CREDITS
11 * files for more information.
15 * FIXME:
16 * Some of the code in here (the various
17 * foo_slots[], at least) is deeply broken, depending on guessing
18 * already out-of-date values instead of getting them from sbcl.h.
21 #include <stdio.h>
22 #include <string.h>
24 #include "sbcl.h"
25 #include "print.h"
26 #include "runtime.h"
27 #include <stdarg.h>
28 #include "thread.h" /* genesis/primitive-objects.h needs this */
29 #include <errno.h>
30 #include <stdlib.h>
32 /* FSHOW and odxprint provide debugging output for low-level information
33 * (signal handling, exceptions, safepoints) which is hard to debug by
34 * other means.
36 * If enabled at all, environment variables control whether calls of the
37 * form odxprint(name, ...) are enabled at run-time, e.g. using
38 * SBCL_DYNDEBUG="fshow fshow_signal safepoints".
40 * In the case of FSHOW and FSHOW_SIGNAL, old-style code from runtime.h
41 * can also be used to enable or disable these more aggressively.
44 struct dyndebug_config dyndebug_config = {
45 QSHOW == 2, QSHOW_SIGNALS == 2
48 void
49 dyndebug_init()
51 #define DYNDEBUG_NFLAGS (sizeof(struct dyndebug_config) / sizeof(int))
52 #define dyndebug_init1(lowercase, uppercase) \
53 do { \
54 int *ptr = &dyndebug_config.dyndebug_##lowercase; \
55 ptrs[n] = ptr; \
56 names[n] = #lowercase; \
57 char *val = getenv("SBCL_DYNDEBUG__" uppercase); \
58 *ptr = val && strlen(val); \
59 n++; \
60 } while (0)
61 int n = 0;
62 char *names[DYNDEBUG_NFLAGS];
63 int *ptrs[DYNDEBUG_NFLAGS];
65 dyndebug_init1(fshow, "FSHOW");
66 dyndebug_init1(fshow_signal, "FSHOW_SIGNAL");
67 dyndebug_init1(gencgc_verbose, "GENCGC_VERBOSE");
68 dyndebug_init1(safepoints, "SAFEPOINTS");
69 dyndebug_init1(seh, "SEH");
70 dyndebug_init1(misc, "MISC");
71 dyndebug_init1(pagefaults, "PAGEFAULTS");
72 dyndebug_init1(io, "IO");
73 dyndebug_init1(runtime_link, "RUNTIME_LINK");
75 int n_output_flags = n;
76 dyndebug_init1(backtrace_when_lost, "BACKTRACE_WHEN_LOST");
77 dyndebug_init1(sleep_when_lost, "SLEEP_WHEN_LOST");
79 if (n != DYNDEBUG_NFLAGS)
80 fprintf(stderr, "Bug in dyndebug_init\n");
82 #if defined(LISP_FEATURE_GENCGC)
83 gencgc_verbose = dyndebug_config.dyndebug_gencgc_verbose;
84 #endif
86 char *featurelist = getenv("SBCL_DYNDEBUG");
87 if (featurelist) {
88 int err = 0;
89 featurelist = strdup(featurelist);
90 char *ptr = featurelist;
91 for (;;) {
92 char *token = strtok(ptr, " ");
93 if (!token) break;
94 int i;
95 if (!strcmp(token, "all"))
96 for (i = 0; i < n_output_flags; i++)
97 *ptrs[i] = 1;
98 else {
99 for (i = 0; i < (int)DYNDEBUG_NFLAGS; i++)
100 if (!strcmp(token, names[i])) {
101 *ptrs[i] = 1;
102 break;
104 if (i == DYNDEBUG_NFLAGS) {
105 fprintf(stderr, "No such dyndebug flag: `%s'\n", token);
106 err = 1;
109 ptr = 0;
111 free(featurelist);
112 if (err) {
113 fprintf(stderr, "Valid flags are:\n");
114 fprintf(stderr, " all ;enables all of the following:\n");
115 int i;
116 for (i = 0; i < (int)DYNDEBUG_NFLAGS; i++) {
117 if (i == n_output_flags)
118 fprintf(stderr, "Additional options:\n");
119 fprintf(stderr, " %s\n", names[i]);
124 #undef dyndebug_init1
125 #undef DYNDEBUG_NFLAGS
128 /* Temporarily, odxprint merely performs the equivalent of a traditional
129 * FSHOW call, i.e. it merely formats to stderr. Ultimately, it should
130 * be restored to its full win32 branch functionality, where output to a
131 * file or to the debugger can be selected at runtime. */
133 void vodxprint_fun(const char *, va_list);
135 void
136 odxprint_fun(const char *fmt, ...)
138 va_list args;
139 va_start(args, fmt);
140 vodxprint_fun(fmt, args);
141 va_end(args);
144 void
145 vodxprint_fun(const char *fmt, va_list args)
147 #ifdef LISP_FEATURE_WIN32
148 DWORD lastError = GetLastError();
149 #endif
150 int original_errno = errno;
152 QSHOW_BLOCK;
154 char buf[1024];
155 int n = 0;
157 #ifdef LISP_FEATURE_SB_THREAD
158 struct thread *arch_os_get_current_thread(void);
159 struct thread *self = arch_os_get_current_thread();
160 void *pth = self ? (void *) self->os_thread : 0;
161 snprintf(buf, sizeof(buf), "[%p/%p] ", self, pth);
162 n = strlen(buf);
163 #endif
165 vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, args);
166 /* buf is now zero-terminated (even in case of overflow).
167 * Our caller took care of the newline (if any) through `fmt'. */
169 /* A sufficiently POSIXy implementation of stdio will provide
170 * per-FILE locking, as defined in the spec for flockfile. At least
171 * glibc complies with this. Hence we do not need to perform
172 * locking ourselves here. (Should it turn out, of course, that
173 * other libraries opt for speed rather than safety, we need to
174 * revisit this decision.) */
175 fputs(buf, stderr);
177 #ifdef LISP_FEATURE_WIN32
178 /* stdio's stderr is line-bufferred, i.e. \n ought to flush it.
179 * Unfortunately, MinGW does not behave the way I would expect it
180 * to. Let's be safe: */
181 fflush(stderr);
182 #endif
184 QSHOW_UNBLOCK;
186 #ifdef LISP_FEATURE_WIN32
187 SetLastError(lastError);
188 #endif
189 errno = original_errno;
192 /* Translate the rather awkward syntax
193 * FSHOW((stderr, "xyz"))
194 * into the new and cleaner
195 * odxprint("xyz").
196 * If we were willing to clean up all existing call sites, we could remove
197 * this wrapper function. (This is a function, because I don't know how to
198 * strip the extra parens in a macro.) */
199 void
200 fshow_fun(void __attribute__((__unused__)) *ignored,
201 const char *fmt,
202 ...)
204 va_list args;
205 va_start(args, fmt);
206 vodxprint_fun(fmt, args);
207 va_end(args);
210 /* This file can be skipped if we're not supporting LDB. */
211 #if defined(LISP_FEATURE_SB_LDB)
213 #include "monitor.h"
214 #include "vars.h"
215 #include "os.h"
216 #ifdef LISP_FEATURE_GENCGC
217 #include "gencgc-alloc-region.h" /* genesis/thread.h needs this */
218 #endif
219 #if defined(LISP_FEATURE_WIN32)
220 # include "win32-thread-private-events.h" /* genesis/thread.h needs this */
221 #endif
222 #include "genesis/static-symbols.h"
223 #include "genesis/primitive-objects.h"
224 #include "genesis/static-symbols.h"
225 #include "genesis/tagnames.h"
227 static int max_lines = 20, cur_lines = 0;
228 static int max_depth = 5, brief_depth = 2, cur_depth = 0;
229 static int max_length = 5;
230 static boolean dont_descend = 0, skip_newline = 0;
231 static int cur_clock = 0;
233 static void print_obj(char *prefix, lispobj obj);
235 #define NEWLINE_OR_RETURN if (continue_p(1)) newline(NULL); else return;
237 static void indent(int in)
239 static char *spaces = " ";
241 while (in > 64) {
242 fputs(spaces, stdout);
243 in -= 64;
245 if (in != 0)
246 fputs(spaces + 64 - in, stdout);
249 static boolean continue_p(boolean newline)
251 char buffer[256];
253 if (cur_depth >= max_depth || dont_descend)
254 return 0;
256 if (newline) {
257 if (skip_newline)
258 skip_newline = 0;
259 else
260 putchar('\n');
262 if (cur_lines >= max_lines) {
263 printf("More? [y] ");
264 fflush(stdout);
266 if (fgets(buffer, sizeof(buffer), stdin)) {
267 if (buffer[0] == 'n' || buffer[0] == 'N')
268 throw_to_monitor();
269 else
270 cur_lines = 0;
271 } else {
272 printf("\nUnable to read response, assuming y.\n");
273 cur_lines = 0;
278 return 1;
281 static void newline(char *label)
283 cur_lines++;
284 if (label != NULL)
285 fputs(label, stdout);
286 putchar('\t');
287 indent(cur_depth * 2);
291 static void print_unknown(lispobj obj)
293 printf("unknown object: %p", (void *)obj);
296 static void brief_fixnum(lispobj obj)
298 /* KLUDGE: Rather than update the tables in print_obj(), we
299 declare all fixnum-or-unknown tags to be fixnums and sort it
300 out here with a guard clause. */
301 if (!fixnump(obj)) return print_unknown(obj);
303 #ifndef LISP_FEATURE_ALPHA
304 printf("%ld", ((long)obj)>>N_FIXNUM_TAG_BITS);
305 #else
306 printf("%d", ((s32)obj)>>N_FIXNUM_TAG_BITS);
307 #endif
310 static void print_fixnum(lispobj obj)
312 /* KLUDGE: Rather than update the tables in print_obj(), we
313 declare all fixnum-or-unknown tags to be fixnums and sort it
314 out here with a guard clause. */
315 if (!fixnump(obj)) return print_unknown(obj);
317 #ifndef LISP_FEATURE_ALPHA
318 printf(": %ld", ((long)obj)>>N_FIXNUM_TAG_BITS);
319 #else
320 printf(": %d", ((s32)obj)>>N_FIXNUM_TAG_BITS);
321 #endif
324 static void brief_otherimm(lispobj obj)
326 int type, c;
327 char * charname = 0;
329 type = widetag_of(obj);
330 switch (type) {
331 case CHARACTER_WIDETAG:
332 c = obj>>8; // no mask. show whatever's there
333 printf("#\\");
334 switch (c) {
335 case '\0': charname = "Nul"; break;
336 case '\n': charname = "Newline"; break;
337 case '\b': charname = "Backspace"; break;
338 case '\177': charname = "Delete"; break;
339 default:
340 if (c < 32) printf("^%c", c+64);
341 else printf(c < 128 ? "%c" : "U+%X", c);
343 if (charname)
344 fputs(charname, stdout);
345 break;
347 case UNBOUND_MARKER_WIDETAG:
348 printf("<unbound marker>");
349 break;
351 default:
352 printf("%s", widetag_names[type >> 2]);
353 break;
357 static void print_otherimm(lispobj obj)
359 printf(", %s", widetag_names[widetag_of(obj) >> 2]);
361 switch (widetag_of(obj)) {
362 case CHARACTER_WIDETAG:
363 printf(": ");
364 brief_otherimm(obj);
365 break;
367 case SAP_WIDETAG:
368 case UNBOUND_MARKER_WIDETAG:
369 break;
371 default:
372 printf(": data=%"OBJ_FMTX, (obj>>8));
373 break;
377 static void brief_list(lispobj obj)
379 int space = 0;
380 int length = 0;
382 if (!is_valid_lisp_addr((os_vm_address_t)native_pointer(obj)))
383 printf("(invalid Lisp-level address)");
384 else if (obj == NIL)
385 printf("NIL");
386 else {
387 putchar('(');
388 while (lowtag_of(obj) == LIST_POINTER_LOWTAG) {
389 struct cons *cons = (struct cons *)native_pointer(obj);
391 if (space)
392 putchar(' ');
393 if (++length >= max_length) {
394 printf("...");
395 obj = NIL;
396 break;
398 print_obj("", cons->car);
399 obj = cons->cdr;
400 space = 1;
401 if (obj == NIL)
402 break;
404 if (obj != NIL) {
405 printf(" . ");
406 print_obj("", obj);
408 putchar(')');
412 static void print_list(lispobj obj)
414 if (!is_valid_lisp_addr((os_vm_address_t)native_pointer(obj))) {
415 printf("(invalid address)");
416 } else if (obj == NIL) {
417 printf(" (NIL)");
418 } else {
419 struct cons *cons = (struct cons *)native_pointer(obj);
421 print_obj("car: ", cons->car);
422 print_obj("cdr: ", cons->cdr);
426 // takes native pointer as input
427 char * simple_base_stringize(struct vector * string)
429 if (widetag_of(string->header) == SIMPLE_BASE_STRING_WIDETAG)
430 return (char*)string->data;
431 int length = string->length;
432 char * newstring = malloc(length+1);
433 uint32_t * data = (uint32_t*)string->data;
434 int i;
435 for(i=0;i<length;++i)
436 newstring[i] = data[i] < 128 ? data[i] : '?';
437 newstring[length] = 0;
438 return newstring;
441 static void brief_struct(lispobj obj)
443 struct instance *instance = (struct instance *)native_pointer(obj);
444 if (!is_valid_lisp_addr((os_vm_address_t)instance)) {
445 printf("(invalid address)");
446 } else {
447 extern struct vector * instance_classoid_name(lispobj*);
448 struct vector * classoid_name;
449 classoid_name = instance_classoid_name((lispobj*)instance);
450 if ( classoid_name ) {
451 char * namestring = simple_base_stringize(classoid_name);
452 printf("#<ptr to %p %s instance>",
453 (void*)instance_layout((lispobj*)instance), namestring);
454 if ( namestring != (char*)classoid_name->data )
455 free(namestring);
456 } else {
457 printf("#<ptr to %p instance>",
458 (void*)instance_layout((lispobj*)instance));
463 #include "genesis/layout.h"
464 static boolean untagged_slot_p(struct layout * layout,
465 int slot_index)
467 #ifdef LISP_FEATURE_INTERLEAVED_RAW_SLOTS
468 extern boolean positive_bignum_logbitp(int,struct bignum*);
469 lispobj bitmap = layout->untagged_bitmap;
470 return fixnump(bitmap)
471 ? (fixnum_value(bitmap) >> slot_index) & 1
472 : positive_bignum_logbitp(slot_index,
473 (struct bignum*)native_pointer(bitmap));
474 #else
475 // STANDARD-OBJECT has layout-length = number of defined slots, but
476 // the primitive object always occupies 4 physical words. The guard on
477 // n_untagged_slots ensures that for classes with no slots, we don't
478 // wrongly show all words of the primitive object as untagged,
479 // because the second half of the expression reduces to slot_index>=1.
480 return layout->n_untagged_slots > 0
481 && slot_index >= (fixnum_value(layout->length)|1)
482 - fixnum_value(layout->n_untagged_slots);
483 #endif
486 static void print_struct(lispobj obj)
488 struct instance *instance = (struct instance *)native_pointer(obj);
489 unsigned int i;
490 char buffer[16];
491 if (!is_valid_lisp_addr((os_vm_address_t)instance)) {
492 printf("(invalid address)");
493 } else {
494 lispobj layout_obj = instance_layout(native_pointer(obj));
495 print_obj("type: ", layout_obj);
496 struct layout * layout = (struct layout*)native_pointer(layout_obj);
497 for (i=INSTANCE_DATA_START; i<instance_length(instance->header); i++) {
498 sprintf(buffer, "slot %d: ", i);
499 if (layout==NULL || untagged_slot_p(layout, i)) {
500 newline(NULL);
501 printf("\n\t %s0x%"OBJ_FMTX" [raw]", buffer, instance->slots[i]);
502 } else
503 print_obj(buffer, instance->slots[i]);
508 void show_lstring(struct vector * string, int quotes, FILE *s)
510 int ucs4_p = 0;
511 int i, len = fixnum_value(string->length);
513 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
514 if (widetag_of(string->header) == SIMPLE_CHARACTER_STRING_WIDETAG) {
515 ucs4_p = 1;
516 if (quotes)
517 putc('u', s); /* an arbitrary notational convention */
519 #endif
520 if (quotes) putc('"', s);
521 for (i=0 ; i<len ; i++) {
522 // hopefully the compiler will optimize out the ucs4_p test
523 // when the runtime is built without Unicode support
524 int ch;
525 if (ucs4_p)
526 ch = i[(uint32_t*)string->data];
527 else
528 ch = i[(char*)string->data];
529 if (ch >= 32 && ch < 127) {
530 if (quotes && (ch == '"' || ch == '\\'))
531 putc('\\', s);
532 putc(ch, s);
533 } else {
534 fprintf(s, ch > 0xffff ? "\\U%08X" :
535 ch > 0xff ? "\\u%04X" : "\\x%02X", ch);
538 if (quotes) putc('"', s);
541 static void brief_otherptr(lispobj obj)
543 lispobj *ptr, header;
544 int type;
545 struct symbol *symbol;
547 ptr = (lispobj *) native_pointer(obj);
549 if (!is_valid_lisp_addr((os_vm_address_t)obj)) {
550 printf("(invalid address)");
551 return;
554 header = *ptr;
555 type = widetag_of(header);
556 switch (type) {
557 case SYMBOL_HEADER_WIDETAG:
558 symbol = (struct symbol *)ptr;
559 if (symbol->package == NIL)
560 printf("#:");
561 show_lstring((struct vector *)native_pointer(symbol->name),
562 0, stdout);
563 break;
565 case SIMPLE_BASE_STRING_WIDETAG:
566 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
567 case SIMPLE_CHARACTER_STRING_WIDETAG:
568 #endif
569 show_lstring((struct vector*)ptr, 1, stdout);
570 break;
572 default:
573 printf("#<ptr to ");
574 brief_otherimm(header);
575 putchar('>');
579 static void print_slots(char **slots, int count, lispobj *ptr)
581 while (count-- > 0) {
582 if (*slots) {
583 print_obj(*slots++, *ptr++);
584 } else {
585 print_obj("???: ", *ptr++);
590 /* FIXME: Yikes! This needs to depend on the values in sbcl.h (or
591 * perhaps be generated automatically by GENESIS as part of
592 * sbcl.h). */
593 static char *symbol_slots[] = {"value: ", "hash: ",
594 "info: ", "name: ", "package: ",
595 #if defined (LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_X86_64)
596 "tls-index: " ,
597 #endif
598 NULL};
599 static char *ratio_slots[] = {"numer: ", "denom: ", NULL};
600 static char *complex_slots[] = {"real: ", "imag: ", NULL};
601 static char *code_slots[] = {"words: ", "entry: ", "debug: ", NULL};
602 static char *fn_slots[] = {
603 "self: ", "next: ", "name: ", "arglist: ", "type: ", "info: ", NULL};
604 static char *closure_slots[] = {"fn: ", NULL};
605 static char *funcallable_instance_slots[] = {"raw_fn: ", "fn: ", "layout: ", NULL};
606 static char *weak_pointer_slots[] = {"value: ", NULL};
607 static char *fdefn_slots[] = {"name: ", "function: ", "raw_addr: ", NULL};
608 static char *value_cell_slots[] = {"value: ", NULL};
610 static void print_otherptr(lispobj obj)
612 if (!is_valid_lisp_addr((os_vm_address_t)obj)) {
613 printf("(invalid address)");
614 } else {
615 #ifndef LISP_FEATURE_ALPHA
616 lispobj *ptr;
617 unsigned long header;
618 unsigned long length;
619 #else
620 u32 *ptr;
621 u32 header;
622 u32 length;
623 #endif
624 int count, type, index;
625 char buffer[16];
627 ptr = (lispobj*) native_pointer(obj);
628 if (ptr == NULL) {
629 printf(" (NULL Pointer)");
630 return;
633 header = *ptr++;
634 length = fixnum_value(*ptr);
635 count = HeaderValue(header);
636 type = widetag_of(header);
638 print_obj("header: ", header);
639 if (!other_immediate_lowtag_p(header)) {
640 NEWLINE_OR_RETURN;
641 printf("(invalid header object)");
642 return;
645 if (unprintable_array_types[type/8] & (1<<(type % 8)))
646 return;
647 switch (type) {
648 case BIGNUM_WIDETAG:
649 ptr += count;
650 NEWLINE_OR_RETURN;
651 printf("0x");
652 while (count-- > 0)
653 printf(
654 #if N_WORD_BITS == 32
655 "%08lx%s",
656 #else
657 "%016lx%s",
658 #endif
659 (unsigned long) *--ptr, (count?"_":""));
660 break;
662 case RATIO_WIDETAG:
663 print_slots(ratio_slots, count, ptr);
664 break;
666 case COMPLEX_WIDETAG:
667 print_slots(complex_slots, count, ptr);
668 break;
670 case SYMBOL_HEADER_WIDETAG:
671 // Only 1 byte of a symbol header conveys its size.
672 // The other bytes may be freely used by the backend.
673 print_slots(symbol_slots, count & 0xFF, ptr);
674 break;
676 #if N_WORD_BITS == 32
677 case SINGLE_FLOAT_WIDETAG:
678 NEWLINE_OR_RETURN;
679 printf("%g", ((struct single_float *)native_pointer(obj))->value);
680 break;
681 #endif
682 case DOUBLE_FLOAT_WIDETAG:
683 NEWLINE_OR_RETURN;
684 printf("%g", ((struct double_float *)native_pointer(obj))->value);
685 break;
687 #ifdef LONG_FLOAT_WIDETAG
688 case LONG_FLOAT_WIDETAG:
689 NEWLINE_OR_RETURN;
690 printf("%Lg", ((struct long_float *)native_pointer(obj))->value);
691 break;
692 #endif
694 #ifdef COMPLEX_SINGLE_FLOAT_WIDETAG
695 case COMPLEX_SINGLE_FLOAT_WIDETAG:
696 NEWLINE_OR_RETURN;
697 #ifdef LISP_FEATURE_X86_64
698 printf("%g", ((struct complex_single_float *)native_pointer(obj))->data.data[0]);
699 #else
700 printf("%g", ((struct complex_single_float *)native_pointer(obj))->real);
701 #endif
702 NEWLINE_OR_RETURN;
703 #ifdef LISP_FEATURE_X86_64
704 printf("%g", ((struct complex_single_float *)native_pointer(obj))->data.data[1]);
705 #else
706 printf("%g", ((struct complex_single_float *)native_pointer(obj))->imag);
707 #endif
708 break;
709 #endif
711 #ifdef COMPLEX_DOUBLE_FLOAT_WIDETAG
712 case COMPLEX_DOUBLE_FLOAT_WIDETAG:
713 NEWLINE_OR_RETURN;
714 printf("%g", ((struct complex_double_float *)native_pointer(obj))->real);
715 NEWLINE_OR_RETURN;
716 printf("%g", ((struct complex_double_float *)native_pointer(obj))->imag);
717 break;
718 #endif
720 #ifdef COMPLEX_LONG_FLOAT_WIDETAG
721 case COMPLEX_LONG_FLOAT_WIDETAG:
722 NEWLINE_OR_RETURN;
723 printf("%Lg", ((struct complex_long_float *)native_pointer(obj))->real);
724 NEWLINE_OR_RETURN;
725 printf("%Lg", ((struct complex_long_float *)native_pointer(obj))->imag);
726 break;
727 #endif
729 case SIMPLE_BASE_STRING_WIDETAG:
730 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
731 case SIMPLE_CHARACTER_STRING_WIDETAG:
732 #endif
733 NEWLINE_OR_RETURN;
734 show_lstring((struct vector*)native_pointer(obj), 1, stdout);
735 break;
737 case SIMPLE_VECTOR_WIDETAG:
738 NEWLINE_OR_RETURN;
739 printf("length = %ld", length);
740 ptr++;
741 index = 0;
742 while (length-- > 0) {
743 sprintf(buffer, "%d: ", index++);
744 print_obj(buffer, *ptr++);
746 break;
748 // FIXME: This case looks unreachable. print_struct() does it
749 case INSTANCE_HEADER_WIDETAG:
750 NEWLINE_OR_RETURN;
751 printf("length = %ld", (long) count);
752 index = 0;
753 while (count-- > 0) {
754 sprintf(buffer, "%d: ", index++);
755 print_obj(buffer, *ptr++);
757 break;
759 case CODE_HEADER_WIDETAG:
760 print_slots(code_slots, count-1, ptr);
761 break;
763 case SIMPLE_FUN_HEADER_WIDETAG:
764 print_slots(fn_slots, 6, ptr);
765 break;
767 #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
768 case RETURN_PC_HEADER_WIDETAG:
769 print_obj("code: ", obj - (count * 4));
770 break;
771 #endif
773 case CLOSURE_HEADER_WIDETAG:
774 print_slots(closure_slots, count, ptr);
775 break;
777 case FUNCALLABLE_INSTANCE_HEADER_WIDETAG:
778 print_slots(funcallable_instance_slots, count, ptr);
779 break;
781 case VALUE_CELL_HEADER_WIDETAG:
782 print_slots(value_cell_slots, 1, ptr);
783 break;
785 case SAP_WIDETAG:
786 NEWLINE_OR_RETURN;
787 #ifndef LISP_FEATURE_ALPHA
788 printf("0x%08lx", (unsigned long) *ptr);
789 #else
790 printf("0x%016lx", *(lispobj*)(ptr+1));
791 #endif
792 break;
794 case WEAK_POINTER_WIDETAG:
795 print_slots(weak_pointer_slots, 1, ptr);
796 break;
798 case CHARACTER_WIDETAG:
799 case UNBOUND_MARKER_WIDETAG:
800 NEWLINE_OR_RETURN;
801 printf("pointer to an immediate?");
802 break;
804 case FDEFN_WIDETAG:
805 print_slots(fdefn_slots, count, ptr);
806 break;
808 default:
809 NEWLINE_OR_RETURN;
810 printf("Unknown header object?");
811 break;
816 static void print_obj(char *prefix, lispobj obj)
818 #ifdef LISP_FEATURE_X86_64
819 static void (*verbose_fns[])(lispobj obj)
820 = {print_fixnum, print_otherimm, print_fixnum, print_struct,
821 print_fixnum, print_otherimm, print_fixnum, print_list,
822 print_fixnum, print_otherimm, print_fixnum, print_otherptr,
823 print_fixnum, print_otherimm, print_fixnum, print_otherptr};
824 static void (*brief_fns[])(lispobj obj)
825 = {brief_fixnum, brief_otherimm, brief_fixnum, brief_struct,
826 brief_fixnum, brief_otherimm, brief_fixnum, brief_list,
827 brief_fixnum, brief_otherimm, brief_fixnum, brief_otherptr,
828 brief_fixnum, brief_otherimm, brief_fixnum, brief_otherptr};
829 #else
830 static void (*verbose_fns[])(lispobj obj)
831 = {print_fixnum, print_struct, print_otherimm, print_list,
832 print_fixnum, print_otherptr, print_otherimm, print_otherptr};
833 static void (*brief_fns[])(lispobj obj)
834 = {brief_fixnum, brief_struct, brief_otherimm, brief_list,
835 brief_fixnum, brief_otherptr, brief_otherimm, brief_otherptr};
836 #endif
837 int type = lowtag_of(obj);
838 struct var *var = lookup_by_obj(obj);
839 char buffer[256];
840 boolean verbose = cur_depth < brief_depth;
842 if (!continue_p(verbose))
843 return;
845 if (var != NULL && var_clock(var) == cur_clock)
846 dont_descend = 1;
848 if (var == NULL && is_lisp_pointer(obj))
849 var = define_var(NULL, obj, 0);
851 if (var != NULL)
852 var_setclock(var, cur_clock);
854 cur_depth++;
855 if (verbose) {
856 if (var != NULL) {
857 sprintf(buffer, "$%s=", var_name(var));
858 newline(buffer);
860 else
861 newline(NULL);
862 printf("%s0x%08lx: ", prefix, (unsigned long) obj);
863 if (cur_depth < brief_depth) {
864 fputs(lowtag_names[type], stdout);
865 (*verbose_fns[type])(obj);
867 else
868 (*brief_fns[type])(obj);
870 else {
871 if (dont_descend)
872 printf("$%s", var_name(var));
873 else {
874 if (var != NULL)
875 printf("$%s=", var_name(var));
876 (*brief_fns[type])(obj);
879 cur_depth--;
880 dont_descend = 0;
883 void reset_printer()
885 cur_clock++;
886 cur_lines = 0;
887 dont_descend = 0;
890 void print(lispobj obj)
892 skip_newline = 1;
893 cur_depth = 0;
894 max_depth = 5;
895 max_lines = 20;
897 print_obj("", obj);
899 putchar('\n');
902 void brief_print(lispobj obj)
904 skip_newline = 1;
905 cur_depth = 0;
906 max_depth = 1;
907 max_lines = 5000;
908 cur_lines = 0;
910 print_obj("", obj);
911 putchar('\n');
914 #else
916 void
917 brief_print(lispobj obj)
919 printf("lispobj 0x%lx\n", (unsigned long)obj);
922 #endif /* defined(LISP_FEATURE_SB_LDB) */