1 /* code for low-level debugging/diagnostic output */
4 * This software is part of the SBCL system. See the README file for
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.
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.
27 #include "gc-internal.h"
29 #include "thread.h" /* genesis/primitive-objects.h needs this */
33 /* FSHOW and odxprint provide debugging output for low-level information
34 * (signal handling, exceptions, safepoints) which is hard to debug by
37 * If enabled at all, environment variables control whether calls of the
38 * form odxprint(name, ...) are enabled at run-time, e.g. using
39 * SBCL_DYNDEBUG="fshow fshow_signal safepoints".
41 * In the case of FSHOW and FSHOW_SIGNAL, old-style code from runtime.h
42 * can also be used to enable or disable these more aggressively.
45 struct dyndebug_config dyndebug_config
= {
46 QSHOW
== 2, QSHOW_SIGNALS
== 2
52 #define DYNDEBUG_NFLAGS (sizeof(struct dyndebug_config) / sizeof(int))
53 #define dyndebug_init1(lowercase, uppercase) \
55 int *ptr = &dyndebug_config.dyndebug_##lowercase; \
57 names[n] = #lowercase; \
58 char *val = getenv("SBCL_DYNDEBUG__" uppercase); \
59 *ptr = val && strlen(val); \
63 char *names
[DYNDEBUG_NFLAGS
];
64 int *ptrs
[DYNDEBUG_NFLAGS
];
66 dyndebug_init1(fshow
, "FSHOW");
67 dyndebug_init1(fshow_signal
, "FSHOW_SIGNAL");
68 dyndebug_init1(gencgc_verbose
, "GENCGC_VERBOSE");
69 dyndebug_init1(safepoints
, "SAFEPOINTS");
70 dyndebug_init1(seh
, "SEH");
71 dyndebug_init1(misc
, "MISC");
72 dyndebug_init1(pagefaults
, "PAGEFAULTS");
73 dyndebug_init1(io
, "IO");
74 dyndebug_init1(runtime_link
, "RUNTIME_LINK");
76 int n_output_flags
= n
;
77 dyndebug_init1(backtrace_when_lost
, "BACKTRACE_WHEN_LOST");
78 dyndebug_init1(sleep_when_lost
, "SLEEP_WHEN_LOST");
80 if (n
!= DYNDEBUG_NFLAGS
)
81 fprintf(stderr
, "Bug in dyndebug_init\n");
83 #if defined(LISP_FEATURE_GENCGC)
84 gencgc_verbose
= dyndebug_config
.dyndebug_gencgc_verbose
;
87 char *featurelist
= getenv("SBCL_DYNDEBUG");
90 featurelist
= strdup(featurelist
);
91 char *ptr
= featurelist
;
93 char *token
= strtok(ptr
, " ");
96 if (!strcmp(token
, "all"))
97 for (i
= 0; i
< n_output_flags
; i
++)
100 for (i
= 0; i
< (int)DYNDEBUG_NFLAGS
; i
++)
101 if (!strcmp(token
, names
[i
])) {
105 if (i
== DYNDEBUG_NFLAGS
) {
106 fprintf(stderr
, "No such dyndebug flag: `%s'\n", token
);
114 fprintf(stderr
, "Valid flags are:\n");
115 fprintf(stderr
, " all ;enables all of the following:\n");
117 for (i
= 0; i
< (int)DYNDEBUG_NFLAGS
; i
++) {
118 if (i
== n_output_flags
)
119 fprintf(stderr
, "Additional options:\n");
120 fprintf(stderr
, " %s\n", names
[i
]);
125 #undef dyndebug_init1
126 #undef DYNDEBUG_NFLAGS
129 /* Temporarily, odxprint merely performs the equivalent of a traditional
130 * FSHOW call, i.e. it merely formats to stderr. Ultimately, it should
131 * be restored to its full win32 branch functionality, where output to a
132 * file or to the debugger can be selected at runtime. */
134 void vodxprint_fun(const char *, va_list);
137 odxprint_fun(const char *fmt
, ...)
141 vodxprint_fun(fmt
, args
);
146 vodxprint_fun(const char *fmt
, va_list args
)
148 #ifdef LISP_FEATURE_WIN32
149 DWORD lastError
= GetLastError();
151 int original_errno
= errno
;
158 #ifdef LISP_FEATURE_SB_THREAD
159 struct thread
*arch_os_get_current_thread(void);
160 struct thread
*self
= arch_os_get_current_thread();
161 void *pth
= self
? (void *) self
->os_thread
: 0;
162 snprintf(buf
, sizeof(buf
), "[%p/%p] ", self
, pth
);
166 vsnprintf(buf
+ n
, sizeof(buf
) - n
- 1, fmt
, args
);
167 /* buf is now zero-terminated (even in case of overflow).
168 * Our caller took care of the newline (if any) through `fmt'. */
170 /* A sufficiently POSIXy implementation of stdio will provide
171 * per-FILE locking, as defined in the spec for flockfile. At least
172 * glibc complies with this. Hence we do not need to perform
173 * locking ourselves here. (Should it turn out, of course, that
174 * other libraries opt for speed rather than safety, we need to
175 * revisit this decision.) */
178 #ifdef LISP_FEATURE_WIN32
179 /* stdio's stderr is line-bufferred, i.e. \n ought to flush it.
180 * Unfortunately, MinGW does not behave the way I would expect it
181 * to. Let's be safe: */
187 #ifdef LISP_FEATURE_WIN32
188 SetLastError(lastError
);
190 errno
= original_errno
;
193 /* Translate the rather awkward syntax
194 * FSHOW((stderr, "xyz"))
195 * into the new and cleaner
197 * If we were willing to clean up all existing call sites, we could remove
198 * this wrapper function. (This is a function, because I don't know how to
199 * strip the extra parens in a macro.) */
201 fshow_fun(void __attribute__((__unused__
)) *ignored
,
207 vodxprint_fun(fmt
, args
);
211 /* This file can be skipped if we're not supporting LDB. */
212 #if defined(LISP_FEATURE_SB_LDB)
217 #ifdef LISP_FEATURE_GENCGC
218 #include "gencgc-alloc-region.h" /* genesis/thread.h needs this */
220 #if defined(LISP_FEATURE_WIN32)
221 # include "win32-thread-private-events.h" /* genesis/thread.h needs this */
223 #include "genesis/static-symbols.h"
224 #include "genesis/primitive-objects.h"
225 #include "genesis/static-symbols.h"
226 #include "genesis/tagnames.h"
228 static int max_lines
= 20, cur_lines
= 0;
229 static int max_depth
= 5, brief_depth
= 2, cur_depth
= 0;
230 static int max_length
= 5;
231 static boolean dont_descend
= 0, skip_newline
= 0;
232 static int cur_clock
= 0;
234 static void print_obj(char *prefix
, lispobj obj
);
236 #define NEWLINE_OR_RETURN if (continue_p(1)) newline(NULL); else return;
238 static void indent(int in
)
240 static char *spaces
= " ";
243 fputs(spaces
, stdout
);
247 fputs(spaces
+ 64 - in
, stdout
);
250 static boolean
continue_p(boolean newline
)
254 if (cur_depth
>= max_depth
|| dont_descend
)
263 if (cur_lines
>= max_lines
) {
264 printf("More? [y] ");
267 if (fgets(buffer
, sizeof(buffer
), stdin
)) {
268 if (buffer
[0] == 'n' || buffer
[0] == 'N')
273 printf("\nUnable to read response, assuming y.\n");
282 static void newline(char *label
)
286 fputs(label
, stdout
);
288 indent(cur_depth
* 2);
292 static void print_unknown(lispobj obj
)
294 printf("unknown object: %p", (void *)obj
);
297 static void brief_fixnum(lispobj obj
)
299 /* KLUDGE: Rather than update the tables in print_obj(), we
300 declare all fixnum-or-unknown tags to be fixnums and sort it
301 out here with a guard clause. */
302 if (!fixnump(obj
)) return print_unknown(obj
);
304 #ifndef LISP_FEATURE_ALPHA
305 printf("%ld", ((long)obj
)>>N_FIXNUM_TAG_BITS
);
307 printf("%d", ((s32
)obj
)>>N_FIXNUM_TAG_BITS
);
311 static void print_fixnum(lispobj obj
)
313 /* KLUDGE: Rather than update the tables in print_obj(), we
314 declare all fixnum-or-unknown tags to be fixnums and sort it
315 out here with a guard clause. */
316 if (!fixnump(obj
)) return print_unknown(obj
);
318 #ifndef LISP_FEATURE_ALPHA
319 printf(": %ld", ((long)obj
)>>N_FIXNUM_TAG_BITS
);
321 printf(": %d", ((s32
)obj
)>>N_FIXNUM_TAG_BITS
);
325 static void brief_otherimm(lispobj obj
)
330 type
= widetag_of(obj
);
332 case CHARACTER_WIDETAG
:
333 c
= obj
>>8; // no mask. show whatever's there
336 case '\0': charname
= "Nul"; break;
337 case '\n': charname
= "Newline"; break;
338 case '\b': charname
= "Backspace"; break;
339 case '\177': charname
= "Delete"; break;
341 if (c
< 32) printf("^%c", c
+64);
342 else printf(c
< 128 ? "%c" : "U+%X", c
);
345 fputs(charname
, stdout
);
348 case UNBOUND_MARKER_WIDETAG
:
349 printf("<unbound marker>");
353 printf("%s", widetag_names
[type
>> 2]);
358 static void print_otherimm(lispobj obj
)
360 printf(", %s", widetag_names
[widetag_of(obj
) >> 2]);
362 switch (widetag_of(obj
)) {
363 case CHARACTER_WIDETAG
:
369 case UNBOUND_MARKER_WIDETAG
:
373 printf(": data=%"OBJ_FMTX
, (obj
>>8));
378 static void brief_list(lispobj obj
)
383 if (!is_valid_lisp_addr((os_vm_address_t
)native_pointer(obj
)))
384 printf("(invalid Lisp-level address)");
389 while (lowtag_of(obj
) == LIST_POINTER_LOWTAG
) {
390 struct cons
*cons
= (struct cons
*)native_pointer(obj
);
394 if (++length
>= max_length
) {
399 print_obj("", cons
->car
);
413 static void print_list(lispobj obj
)
415 if (!is_valid_lisp_addr((os_vm_address_t
)native_pointer(obj
))) {
416 printf("(invalid address)");
417 } else if (obj
== NIL
) {
420 struct cons
*cons
= (struct cons
*)native_pointer(obj
);
422 print_obj("car: ", cons
->car
);
423 print_obj("cdr: ", cons
->cdr
);
427 // takes native pointer as input
428 char * simple_base_stringize(struct vector
* string
)
430 if (widetag_of(string
->header
) == SIMPLE_BASE_STRING_WIDETAG
)
431 return (char*)string
->data
;
432 int length
= string
->length
;
433 char * newstring
= malloc(length
+1);
434 uint32_t * data
= (uint32_t*)string
->data
;
436 for(i
=0;i
<length
;++i
)
437 newstring
[i
] = data
[i
] < 128 ? data
[i
] : '?';
438 newstring
[length
] = 0;
442 static void brief_struct(lispobj obj
)
444 struct instance
*instance
= (struct instance
*)native_pointer(obj
);
445 if (!is_valid_lisp_addr((os_vm_address_t
)instance
)) {
446 printf("(invalid address)");
448 extern struct vector
* instance_classoid_name(lispobj
*);
449 struct vector
* classoid_name
;
450 classoid_name
= instance_classoid_name((lispobj
*)instance
);
451 if ( classoid_name
) {
452 char * namestring
= simple_base_stringize(classoid_name
);
453 printf("#<ptr to %p %s instance>",
454 (void*)instance_layout((lispobj
*)instance
), namestring
);
455 if ( namestring
!= (char*)classoid_name
->data
)
458 printf("#<ptr to %p instance>",
459 (void*)instance_layout((lispobj
*)instance
));
464 #include "genesis/layout.h"
465 static boolean
tagged_slot_p(struct layout
* layout
,
468 extern boolean
positive_bignum_logbitp(int,struct bignum
*);
469 lispobj bitmap
= layout
->bitmap
;
470 sword_t fixnum
= (sword_t
)bitmap
>> N_FIXNUM_TAG_BITS
; // optimistically
471 return fixnump(bitmap
)
472 ? bitmap
== make_fixnum(-1) ||
473 (slot_index
< N_WORD_BITS
&& ((fixnum
>> slot_index
) & 1) != 0)
474 : positive_bignum_logbitp(slot_index
,
475 (struct bignum
*)native_pointer(bitmap
));
478 static void print_struct(lispobj obj
)
480 struct instance
*instance
= (struct instance
*)native_pointer(obj
);
483 if (!is_valid_lisp_addr((os_vm_address_t
)instance
)) {
484 printf("(invalid address)");
486 lispobj layout_obj
= instance_layout(native_pointer(obj
));
487 print_obj("type: ", layout_obj
);
488 struct layout
* layout
= (struct layout
*)native_pointer(layout_obj
);
489 for (i
=INSTANCE_DATA_START
; i
<instance_length(instance
->header
); i
++) {
490 sprintf(buffer
, "slot %d: ", i
);
491 if (layout
!= NULL
&& tagged_slot_p(layout
, i
)) {
492 print_obj(buffer
, instance
->slots
[i
]);
495 printf("\n\t %s0x%"OBJ_FMTX
" [raw]", buffer
, instance
->slots
[i
]);
501 void show_lstring(struct vector
* string
, int quotes
, FILE *s
)
504 int i
, len
= fixnum_value(string
->length
);
506 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
507 if (widetag_of(string
->header
) == SIMPLE_CHARACTER_STRING_WIDETAG
) {
510 putc('u', s
); /* an arbitrary notational convention */
513 if (quotes
) putc('"', s
);
514 for (i
=0 ; i
<len
; i
++) {
515 // hopefully the compiler will optimize out the ucs4_p test
516 // when the runtime is built without Unicode support
519 ch
= i
[(uint32_t*)string
->data
];
521 ch
= i
[(char*)string
->data
];
522 if (ch
>= 32 && ch
< 127) {
523 if (quotes
&& (ch
== '"' || ch
== '\\'))
527 fprintf(s
, ch
> 0xffff ? "\\U%08X" :
528 ch
> 0xff ? "\\u%04X" : "\\x%02X", ch
);
531 if (quotes
) putc('"', s
);
534 static void brief_otherptr(lispobj obj
)
536 lispobj
*ptr
, header
;
538 struct symbol
*symbol
;
540 ptr
= (lispobj
*) native_pointer(obj
);
542 if (!is_valid_lisp_addr((os_vm_address_t
)obj
)) {
543 printf("(invalid address)");
548 type
= widetag_of(header
);
550 case SYMBOL_HEADER_WIDETAG
:
551 symbol
= (struct symbol
*)ptr
;
552 if (symbol
->package
== NIL
)
554 show_lstring((struct vector
*)native_pointer(symbol
->name
),
558 case SIMPLE_BASE_STRING_WIDETAG
:
559 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
560 case SIMPLE_CHARACTER_STRING_WIDETAG
:
562 show_lstring((struct vector
*)ptr
, 1, stdout
);
567 brief_otherimm(header
);
572 static void print_slots(char **slots
, int count
, lispobj
*ptr
)
574 while (count
-- > 0) {
576 print_obj(*slots
++, *ptr
++);
578 print_obj("???: ", *ptr
++);
583 /* FIXME: Yikes! This needs to depend on the values in sbcl.h (or
584 * perhaps be generated automatically by GENESIS as part of
586 static char *symbol_slots
[] = {"value: ", "hash: ",
587 "info: ", "name: ", "package: ",
588 #if defined (LISP_FEATURE_SB_THREAD) && !defined(LISP_FEATURE_X86_64)
592 static char *ratio_slots
[] = {"numer: ", "denom: ", NULL
};
593 static char *complex_slots
[] = {"real: ", "imag: ", NULL
};
594 static char *code_slots
[] = {"bytes: ", "debug: ", NULL
};
595 static char *fn_slots
[] = {
596 "self: ", "name: ", "arglist: ", "type: ", "info: ", NULL
};
597 static char *closure_slots
[] = {"fn: ", NULL
};
598 static char *funcallable_instance_slots
[] = {"raw_fn: ", "fn: ", "layout: ", NULL
};
599 static char *weak_pointer_slots
[] = {"value: ", NULL
};
600 static char *fdefn_slots
[] = {"name: ", "function: ", "raw_addr: ", NULL
};
601 static char *value_cell_slots
[] = {"value: ", NULL
};
603 static void print_otherptr(lispobj obj
)
605 if (!is_valid_lisp_addr((os_vm_address_t
)obj
)) {
606 printf("(invalid address)");
608 #ifndef LISP_FEATURE_ALPHA
610 unsigned long header
;
611 unsigned long length
;
617 int count
, type
, index
;
620 ptr
= (lispobj
*) native_pointer(obj
);
622 printf(" (NULL Pointer)");
627 length
= fixnum_value(*ptr
);
628 count
= HeaderValue(header
);
629 type
= widetag_of(header
);
631 print_obj("header: ", header
);
632 if (!other_immediate_lowtag_p(header
)) {
634 printf("(invalid header object)");
638 if (unprintable_array_types
[type
/8] & (1<<(type
% 8)))
647 #if N_WORD_BITS == 32
652 (unsigned long) *--ptr
, (count
?"_":""));
656 print_slots(ratio_slots
, count
, ptr
);
659 case COMPLEX_WIDETAG
:
660 print_slots(complex_slots
, count
, ptr
);
663 case SYMBOL_HEADER_WIDETAG
:
664 // Only 1 byte of a symbol header conveys its size.
665 // The other bytes may be freely used by the backend.
666 print_slots(symbol_slots
, count
& 0xFF, ptr
);
669 #if N_WORD_BITS == 32
670 case SINGLE_FLOAT_WIDETAG
:
672 printf("%g", ((struct single_float
*)native_pointer(obj
))->value
);
675 case DOUBLE_FLOAT_WIDETAG
:
677 printf("%g", ((struct double_float
*)native_pointer(obj
))->value
);
680 #ifdef LONG_FLOAT_WIDETAG
681 case LONG_FLOAT_WIDETAG
:
683 printf("%Lg", ((struct long_float
*)native_pointer(obj
))->value
);
687 #ifdef COMPLEX_SINGLE_FLOAT_WIDETAG
688 case COMPLEX_SINGLE_FLOAT_WIDETAG
:
690 #ifdef LISP_FEATURE_64_BIT
691 printf("%g", ((struct complex_single_float
*)native_pointer(obj
))->data
.data
[0]);
693 printf("%g", ((struct complex_single_float
*)native_pointer(obj
))->real
);
696 #ifdef LISP_FEATURE_64_BIT
697 printf("%g", ((struct complex_single_float
*)native_pointer(obj
))->data
.data
[1]);
699 printf("%g", ((struct complex_single_float
*)native_pointer(obj
))->imag
);
704 #ifdef COMPLEX_DOUBLE_FLOAT_WIDETAG
705 case COMPLEX_DOUBLE_FLOAT_WIDETAG
:
707 printf("%g", ((struct complex_double_float
*)native_pointer(obj
))->real
);
709 printf("%g", ((struct complex_double_float
*)native_pointer(obj
))->imag
);
713 #ifdef COMPLEX_LONG_FLOAT_WIDETAG
714 case COMPLEX_LONG_FLOAT_WIDETAG
:
716 printf("%Lg", ((struct complex_long_float
*)native_pointer(obj
))->real
);
718 printf("%Lg", ((struct complex_long_float
*)native_pointer(obj
))->imag
);
722 case SIMPLE_BASE_STRING_WIDETAG
:
723 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
724 case SIMPLE_CHARACTER_STRING_WIDETAG
:
727 show_lstring((struct vector
*)native_pointer(obj
), 1, stdout
);
730 case SIMPLE_VECTOR_WIDETAG
:
732 printf("length = %ld", length
);
735 while (length
-- > 0) {
736 sprintf(buffer
, "%d: ", index
++);
737 print_obj(buffer
, *ptr
++);
741 // FIXME: This case looks unreachable. print_struct() does it
742 case INSTANCE_HEADER_WIDETAG
:
744 count
&= SHORT_HEADER_MAX_WORDS
;
745 printf("length = %ld", (long) count
);
747 while (count
-- > 0) {
748 sprintf(buffer
, "%d: ", index
++);
749 print_obj(buffer
, *ptr
++);
753 case CODE_HEADER_WIDETAG
:
754 count
&= SHORT_HEADER_MAX_WORDS
;
755 // ptr was already bumped up
756 for_each_simple_fun(fun_index
, fun
, (struct code
*)(ptr
-1), 0, {
757 sprintf(buffer
, "f[%d]: ", fun_index
);
758 print_obj(buffer
, make_lispobj(fun
,FUN_POINTER_LOWTAG
));
760 print_slots(code_slots
, count
-1, ptr
);
763 case SIMPLE_FUN_HEADER_WIDETAG
:
764 print_slots(fn_slots
, 6, ptr
);
767 #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
768 case RETURN_PC_HEADER_WIDETAG
:
769 print_obj("code: ", obj
- (count
* 4));
773 case CLOSURE_HEADER_WIDETAG
:
774 print_slots(closure_slots
, count
, ptr
);
777 case FUNCALLABLE_INSTANCE_HEADER_WIDETAG
:
778 print_slots(funcallable_instance_slots
, count
, ptr
);
781 case VALUE_CELL_HEADER_WIDETAG
:
782 print_slots(value_cell_slots
, 1, ptr
);
787 #ifndef LISP_FEATURE_ALPHA
788 printf("0x%08lx", (unsigned long) *ptr
);
790 printf("0x%016lx", *(lispobj
*)(ptr
+1));
794 case WEAK_POINTER_WIDETAG
:
795 print_slots(weak_pointer_slots
, 1, ptr
);
798 case CHARACTER_WIDETAG
:
799 case UNBOUND_MARKER_WIDETAG
:
801 printf("pointer to an immediate?");
805 print_slots(fdefn_slots
, count
& SHORT_HEADER_MAX_WORDS
, ptr
);
810 printf("Unknown header object?");
816 static void print_obj(char *prefix
, lispobj obj
)
818 #ifdef LISP_FEATURE_64_BIT
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
};
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
};
837 int type
= lowtag_of(obj
);
838 struct var
*var
= lookup_by_obj(obj
);
840 boolean verbose
= cur_depth
< brief_depth
;
842 if (!continue_p(verbose
))
845 if (var
!= NULL
&& var_clock(var
) == cur_clock
)
848 if (var
== NULL
&& is_lisp_pointer(obj
))
849 var
= define_var(NULL
, obj
, 0);
852 var_setclock(var
, cur_clock
);
857 sprintf(buffer
, "$%s=", var_name(var
));
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
);
868 (*brief_fns
[type
])(obj
);
872 printf("$%s", var_name(var
));
875 printf("$%s=", var_name(var
));
876 (*brief_fns
[type
])(obj
);
890 void print(lispobj obj
)
902 void brief_print(lispobj obj
)
917 brief_print(lispobj obj
)
919 printf("lispobj 0x%lx\n", (unsigned long)obj
);
922 #endif /* defined(LISP_FEATURE_SB_LDB) */