Extend use of the linkage table to static symbols
[sbcl.git] / src / runtime / print.c
1 /* code for low-level debugging/diagnostic output */
2
3 /*
4  * This software is part of the SBCL system. See the README file for
5  * more information.
6  *
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.
12  */
13
14 /*
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.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23
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>
31
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.
35  *
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".
39  *
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.
42  */
43
44 struct dyndebug_config dyndebug_config = {
45     QSHOW == 2, QSHOW_SIGNALS == 2
46 };
47
48 void
49 dyndebug_init()
50 {
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];
64
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");
74
75     int n_output_flags = n;
76     dyndebug_init1(backtrace_when_lost, "BACKTRACE_WHEN_LOST");
77     dyndebug_init1(sleep_when_lost,     "SLEEP_WHEN_LOST");
78
79     if (n != DYNDEBUG_NFLAGS)
80         fprintf(stderr, "Bug in dyndebug_init\n");
81
82 #if defined(LISP_FEATURE_GENCGC)
83     gencgc_verbose = dyndebug_config.dyndebug_gencgc_verbose;
84 #endif
85
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             unsigned 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 < DYNDEBUG_NFLAGS; i++)
100                     if (!strcmp(token, names[i])) {
101                         *ptrs[i] = 1;
102                         break;
103                     }
104                 if (i == DYNDEBUG_NFLAGS) {
105                     fprintf(stderr, "No such dyndebug flag: `%s'\n", token);
106                     err = 1;
107                 }
108             }
109             ptr = 0;
110         }
111         free(featurelist);
112         if (err) {
113             fprintf(stderr, "Valid flags are:\n");
114             fprintf(stderr, "  all  ;enables all of the following:\n");
115             unsigned i;
116             for (i = 0; i < DYNDEBUG_NFLAGS; i++) {
117                 if (i == n_output_flags)
118                     fprintf(stderr, "Additional options:\n");
119                 fprintf(stderr, "  %s\n", names[i]);
120             }
121         }
122     }
123
124 #undef dyndebug_init1
125 #undef DYNDEBUG_NFLAGS
126 }
127
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. */
132
133 void vodxprint_fun(const char *, va_list);
134
135 void
136 odxprint_fun(const char *fmt, ...)
137 {
138     va_list args;
139     va_start(args, fmt);
140     vodxprint_fun(fmt, args);
141     va_end(args);
142 }
143
144 void
145 vodxprint_fun(const char *fmt, va_list args)
146 {
147 #ifdef LISP_FEATURE_WIN32
148     DWORD lastError = GetLastError();
149 #endif
150     int original_errno = errno;
151
152     QSHOW_BLOCK;
153
154     char buf[1024];
155
156 #ifdef LISP_FEATURE_SB_THREAD
157     struct thread *arch_os_get_current_thread(void);
158     struct thread *self = arch_os_get_current_thread();
159     void *pth = self ? (void *) self->os_thread : 0;
160     snprintf(buf, sizeof(buf), "[%p/%p] ", self, pth);
161 #endif
162
163     int n = strlen(buf);
164     vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, args);
165     /* buf is now zero-terminated (even in case of overflow).
166      * Our caller took care of the newline (if any) through `fmt'. */
167
168     /* A sufficiently POSIXy implementation of stdio will provide
169      * per-FILE locking, as defined in the spec for flockfile.  At least
170      * glibc complies with this.  Hence we do not need to perform
171      * locking ourselves here.  (Should it turn out, of course, that
172      * other libraries opt for speed rather than safety, we need to
173      * revisit this decision.) */
174     fputs(buf, stderr);
175
176 #ifdef LISP_FEATURE_WIN32
177     /* stdio's stderr is line-bufferred, i.e. \n ought to flush it.
178      * Unfortunately, MinGW does not behave the way I would expect it
179      * to.  Let's be safe: */
180     fflush(stderr);
181 #endif
182
183     QSHOW_UNBLOCK;
184
185 #ifdef LISP_FEATURE_WIN32
186     SetLastError(lastError);
187 #endif
188     errno = original_errno;
189 }
190
191 /* Translate the rather awkward syntax
192  *   FSHOW((stderr, "xyz"))
193  * into the new and cleaner
194  *   odxprint("xyz").
195  * If we were willing to clean up all existing call sites, we could remove
196  * this wrapper function.  (This is a function, because I don't know how to
197  * strip the extra parens in a macro.) */
198 void
199 fshow_fun(void __attribute__((__unused__)) *ignored,
200           const char *fmt,
201           ...)
202 {
203     va_list args;
204     va_start(args, fmt);
205     vodxprint_fun(fmt, args);
206     va_end(args);
207 }
208
209 /* This file can be skipped if we're not supporting LDB. */
210 #if defined(LISP_FEATURE_SB_LDB)
211
212 #include "monitor.h"
213 #include "vars.h"
214 #include "os.h"
215 #ifdef LISP_FEATURE_GENCGC
216 #include "gencgc-alloc-region.h" /* genesis/thread.h needs this */
217 #endif
218 #if defined(LISP_FEATURE_WIN32)
219 # include "win32-thread-private-events.h" /* genesis/thread.h needs this */
220 #endif
221 #include "genesis/static-symbols.h"
222 #include "genesis/primitive-objects.h"
223 #include "genesis/static-symbols.h"
224 #include "genesis/tagnames.h"
225
226 static int max_lines = 20, cur_lines = 0;
227 static int max_depth = 5, brief_depth = 2, cur_depth = 0;
228 static int max_length = 5;
229 static boolean dont_descend = 0, skip_newline = 0;
230 static int cur_clock = 0;
231
232 static void print_obj(char *prefix, lispobj obj);
233
234 #define NEWLINE_OR_RETURN if (continue_p(1)) newline(NULL); else return;
235
236 static void indent(int in)
237 {
238     static char *spaces = "                                                                ";
239
240     while (in > 64) {
241         fputs(spaces, stdout);
242         in -= 64;
243     }
244     if (in != 0)
245         fputs(spaces + 64 - in, stdout);
246 }
247
248 static boolean continue_p(boolean newline)
249 {
250     char buffer[256];
251
252     if (cur_depth >= max_depth || dont_descend)
253         return 0;
254
255     if (newline) {
256         if (skip_newline)
257             skip_newline = 0;
258         else
259             putchar('\n');
260
261         if (cur_lines >= max_lines) {
262             printf("More? [y] ");
263             fflush(stdout);
264
265             if (fgets(buffer, sizeof(buffer), stdin)) {
266                 if (buffer[0] == 'n' || buffer[0] == 'N')
267                     throw_to_monitor();
268                 else
269                     cur_lines = 0;
270             } else {
271                 printf("\nUnable to read response, assuming y.\n");
272                 cur_lines = 0;
273             }
274         }
275     }
276
277     return 1;
278 }
279
280 static void newline(char *label)
281 {
282     cur_lines++;
283     if (label != NULL)
284         fputs(label, stdout);
285     putchar('\t');
286     indent(cur_depth * 2);
287 }
288
289
290 static void print_unknown(lispobj obj)
291 {
292   printf("unknown object: %p", (void *)obj);
293 }
294
295 static void brief_fixnum(lispobj obj)
296 {
297     /* KLUDGE: Rather than update the tables in print_obj(), we
298        declare all fixnum-or-unknown tags to be fixnums and sort it
299        out here with a guard clause. */
300     if (!fixnump(obj)) return print_unknown(obj);
301
302 #ifndef LISP_FEATURE_ALPHA
303     printf("%ld", ((long)obj)>>2);
304 #else
305     printf("%d", ((s32)obj)>>2);
306 #endif
307 }
308
309 static void print_fixnum(lispobj obj)
310 {
311     /* KLUDGE: Rather than update the tables in print_obj(), we
312        declare all fixnum-or-unknown tags to be fixnums and sort it
313        out here with a guard clause. */
314     if (!fixnump(obj)) return print_unknown(obj);
315
316 #ifndef LISP_FEATURE_ALPHA
317     printf(": %ld", ((long)obj)>>2);
318 #else
319     printf(": %d", ((s32)obj)>>2);
320 #endif
321 }
322
323 static void brief_otherimm(lispobj obj)
324 {
325     int type, c;
326     char buffer[10];
327
328     type = widetag_of(obj);
329     switch (type) {
330         case CHARACTER_WIDETAG:
331             c = (obj>>8)&0xff;
332             switch (c) {
333                 case '\0':
334                     printf("#\\Null");
335                     break;
336                 case '\n':
337                     printf("#\\Newline");
338                     break;
339                 case '\b':
340                     printf("#\\Backspace");
341                     break;
342                 case '\177':
343                     printf("#\\Delete");
344                     break;
345                 default:
346                     strcpy(buffer, "#\\");
347                     if (c >= 128) {
348                         strcat(buffer, "m-");
349                         c -= 128;
350                     }
351                     if (c < 32) {
352                         strcat(buffer, "c-");
353                         c += '@';
354                     }
355                     printf("%s%c", buffer, c);
356                     break;
357             }
358             break;
359
360         case UNBOUND_MARKER_WIDETAG:
361             printf("<unbound marker>");
362             break;
363
364         default:
365             printf("%s", widetag_names[type >> 2]);
366             break;
367     }
368 }
369
370 static void print_otherimm(lispobj obj)
371 {
372     printf(", %s", widetag_names[widetag_of(obj) >> 2]);
373
374     switch (widetag_of(obj)) {
375         case CHARACTER_WIDETAG:
376             printf(": ");
377             brief_otherimm(obj);
378             break;
379
380         case SAP_WIDETAG:
381         case UNBOUND_MARKER_WIDETAG:
382             break;
383
384         default:
385             printf(": data=%ld", (long) (obj>>8)&0xffffff);
386             break;
387     }
388 }
389
390 static void brief_list(lispobj obj)
391 {
392     int space = 0;
393     int length = 0;
394
395     if (!is_valid_lisp_addr((os_vm_address_t)native_pointer(obj)))
396         printf("(invalid Lisp-level address)");
397     else if (obj == NIL)
398         printf("NIL");
399     else {
400         putchar('(');
401         while (lowtag_of(obj) == LIST_POINTER_LOWTAG) {
402             struct cons *cons = (struct cons *)native_pointer(obj);
403
404             if (space)
405                 putchar(' ');
406             if (++length >= max_length) {
407                 printf("...");
408                 obj = NIL;
409                 break;
410             }
411             print_obj("", cons->car);
412             obj = cons->cdr;
413             space = 1;
414             if (obj == NIL)
415                 break;
416         }
417         if (obj != NIL) {
418             printf(" . ");
419             print_obj("", obj);
420         }
421         putchar(')');
422     }
423 }
424
425 static void print_list(lispobj obj)
426 {
427     if (!is_valid_lisp_addr((os_vm_address_t)native_pointer(obj))) {
428         printf("(invalid address)");
429     } else if (obj == NIL) {
430         printf(" (NIL)");
431     } else {
432         struct cons *cons = (struct cons *)native_pointer(obj);
433
434         print_obj("car: ", cons->car);
435         print_obj("cdr: ", cons->cdr);
436     }
437 }
438
439 static void brief_struct(lispobj obj)
440 {
441     struct instance *instance = (struct instance *)native_pointer(obj);
442     if (!is_valid_lisp_addr((os_vm_address_t)instance)) {
443         printf("(invalid address)");
444     } else {
445         printf("#<ptr to 0x%08lx instance>",
446                (unsigned long) instance->slots[0]);
447     }
448 }
449
450 static void print_struct(lispobj obj)
451 {
452     struct instance *instance = (struct instance *)native_pointer(obj);
453     unsigned int i;
454     char buffer[16];
455     if (!is_valid_lisp_addr((os_vm_address_t)instance)) {
456         printf("(invalid address)");
457     } else {
458         print_obj("type: ", ((struct instance *)native_pointer(obj))->slots[0]);
459         for (i = 1; i < HeaderValue(instance->header); i++) {
460             sprintf(buffer, "slot %d: ", i);
461             print_obj(buffer, instance->slots[i]);
462         }
463     }
464 }
465
466 static void brief_otherptr(lispobj obj)
467 {
468     lispobj *ptr, header;
469     int type;
470     struct symbol *symbol;
471     struct vector *vector;
472     char *charptr;
473
474     ptr = (lispobj *) native_pointer(obj);
475
476     if (!is_valid_lisp_addr((os_vm_address_t)obj)) {
477             printf("(invalid address)");
478             return;
479     }
480
481     header = *ptr;
482     type = widetag_of(header);
483     switch (type) {
484         case SYMBOL_HEADER_WIDETAG:
485             symbol = (struct symbol *)ptr;
486             vector = (struct vector *)native_pointer(symbol->name);
487             for (charptr = (char *)vector->data; *charptr != '\0'; charptr++) {
488                 if (*charptr == '"')
489                     putchar('\\');
490                 putchar(*charptr);
491             }
492             break;
493
494         case SIMPLE_BASE_STRING_WIDETAG:
495             vector = (struct vector *)ptr;
496             putchar('"');
497             for (charptr = (char *)vector->data; *charptr != '\0'; charptr++) {
498                 if (*charptr == '"')
499                     putchar('\\');
500                 putchar(*charptr);
501             }
502             putchar('"');
503             break;
504
505         default:
506             printf("#<ptr to ");
507             brief_otherimm(header);
508             putchar('>');
509     }
510 }
511
512 static void print_slots(char **slots, int count, lispobj *ptr)
513 {
514     while (count-- > 0) {
515         if (*slots) {
516             print_obj(*slots++, *ptr++);
517         } else {
518             print_obj("???: ", *ptr++);
519         }
520     }
521 }
522
523 /* FIXME: Yikes! This needs to depend on the values in sbcl.h (or
524  * perhaps be generated automatically by GENESIS as part of
525  * sbcl.h). */
526 static char *symbol_slots[] = {"value: ", "hash: ",
527     "plist: ", "name: ", "package: ",
528 #ifdef LISP_FEATURE_SB_THREAD
529     "tls-index: " ,
530 #endif
531     NULL};
532 static char *ratio_slots[] = {"numer: ", "denom: ", NULL};
533 static char *complex_slots[] = {"real: ", "imag: ", NULL};
534 static char *code_slots[] = {"words: ", "entry: ", "debug: ", NULL};
535 static char *fn_slots[] = {
536     "self: ", "next: ", "name: ", "arglist: ", "type: ", NULL};
537 static char *closure_slots[] = {"fn: ", NULL};
538 static char *funcallable_instance_slots[] = {"fn: ", "lexenv: ", "layout: ", NULL};
539 static char *weak_pointer_slots[] = {"value: ", NULL};
540 static char *fdefn_slots[] = {"name: ", "function: ", "raw_addr: ", NULL};
541 static char *value_cell_slots[] = {"value: ", NULL};
542
543 static void print_otherptr(lispobj obj)
544 {
545     if (!is_valid_lisp_addr((os_vm_address_t)obj)) {
546         printf("(invalid address)");
547     } else {
548 #ifndef LISP_FEATURE_ALPHA
549         lispobj *ptr;
550         unsigned long header;
551         unsigned long length;
552 #else
553         u32 *ptr;
554         u32 header;
555         u32 length;
556 #endif
557         int count, type, index;
558         char *cptr, buffer[16];
559
560         ptr = (lispobj*) native_pointer(obj);
561         if (ptr == NULL) {
562                 printf(" (NULL Pointer)");
563                 return;
564         }
565
566         header = *ptr++;
567         length = fixnum_value(*ptr);
568         count = HeaderValue(header);
569         type = widetag_of(header);
570
571         print_obj("header: ", header);
572         if (!other_immediate_lowtag_p(header)) {
573             NEWLINE_OR_RETURN;
574             printf("(invalid header object)");
575             return;
576         }
577
578         switch (type) {
579             case BIGNUM_WIDETAG:
580                 ptr += count;
581                 NEWLINE_OR_RETURN;
582                 printf("0x");
583                 while (count-- > 0)
584                     printf("%08lx", (unsigned long) *--ptr);
585                 break;
586
587             case RATIO_WIDETAG:
588                 print_slots(ratio_slots, count, ptr);
589                 break;
590
591             case COMPLEX_WIDETAG:
592                 print_slots(complex_slots, count, ptr);
593                 break;
594
595             case SYMBOL_HEADER_WIDETAG:
596                 print_slots(symbol_slots, count, ptr);
597                 break;
598
599 #if N_WORD_BITS == 32
600             case SINGLE_FLOAT_WIDETAG:
601                 NEWLINE_OR_RETURN;
602                 printf("%g", ((struct single_float *)native_pointer(obj))->value);
603                 break;
604 #endif
605             case DOUBLE_FLOAT_WIDETAG:
606                 NEWLINE_OR_RETURN;
607                 printf("%g", ((struct double_float *)native_pointer(obj))->value);
608                 break;
609
610 #ifdef LONG_FLOAT_WIDETAG
611             case LONG_FLOAT_WIDETAG:
612                 NEWLINE_OR_RETURN;
613                 printf("%Lg", ((struct long_float *)native_pointer(obj))->value);
614                 break;
615 #endif
616
617 #ifdef COMPLEX_SINGLE_FLOAT_WIDETAG
618             case COMPLEX_SINGLE_FLOAT_WIDETAG:
619                 NEWLINE_OR_RETURN;
620 #ifdef LISP_FEATURE_X86_64
621                 printf("%g", ((struct complex_single_float *)native_pointer(obj))->data.data[0]);
622 #else
623                 printf("%g", ((struct complex_single_float *)native_pointer(obj))->real);
624 #endif
625                 NEWLINE_OR_RETURN;
626 #ifdef LISP_FEATURE_X86_64
627                 printf("%g", ((struct complex_single_float *)native_pointer(obj))->data.data[1]);
628 #else
629                 printf("%g", ((struct complex_single_float *)native_pointer(obj))->imag);
630 #endif
631                 break;
632 #endif
633
634 #ifdef COMPLEX_DOUBLE_FLOAT_WIDETAG
635             case COMPLEX_DOUBLE_FLOAT_WIDETAG:
636                 NEWLINE_OR_RETURN;
637                 printf("%g", ((struct complex_double_float *)native_pointer(obj))->real);
638                 NEWLINE_OR_RETURN;
639                 printf("%g", ((struct complex_double_float *)native_pointer(obj))->imag);
640                 break;
641 #endif
642
643 #ifdef COMPLEX_LONG_FLOAT_WIDETAG
644             case COMPLEX_LONG_FLOAT_WIDETAG:
645                 NEWLINE_OR_RETURN;
646                 printf("%Lg", ((struct complex_long_float *)native_pointer(obj))->real);
647                 NEWLINE_OR_RETURN;
648                 printf("%Lg", ((struct complex_long_float *)native_pointer(obj))->imag);
649                 break;
650 #endif
651
652             case SIMPLE_BASE_STRING_WIDETAG:
653 #ifdef SIMPLE_CHARACTER_STRING_WIDETAG
654         case SIMPLE_CHARACTER_STRING_WIDETAG: /* FIXME */
655 #endif
656                 NEWLINE_OR_RETURN;
657                 cptr = (char *)(ptr+1);
658                 putchar('"');
659                 while (length-- > 0)
660                     putchar(*cptr++);
661                 putchar('"');
662                 break;
663
664             case SIMPLE_VECTOR_WIDETAG:
665                 NEWLINE_OR_RETURN;
666                 printf("length = %ld", length);
667                 ptr++;
668                 index = 0;
669                 while (length-- > 0) {
670                     sprintf(buffer, "%d: ", index++);
671                     print_obj(buffer, *ptr++);
672                 }
673                 break;
674
675             case INSTANCE_HEADER_WIDETAG:
676                 NEWLINE_OR_RETURN;
677                 printf("length = %ld", (long) count);
678                 index = 0;
679                 while (count-- > 0) {
680                     sprintf(buffer, "%d: ", index++);
681                     print_obj(buffer, *ptr++);
682                 }
683                 break;
684
685             case SIMPLE_ARRAY_WIDETAG:
686             case SIMPLE_BIT_VECTOR_WIDETAG:
687             case SIMPLE_ARRAY_UNSIGNED_BYTE_2_WIDETAG:
688             case SIMPLE_ARRAY_UNSIGNED_BYTE_4_WIDETAG:
689             case SIMPLE_ARRAY_UNSIGNED_BYTE_7_WIDETAG:
690             case SIMPLE_ARRAY_UNSIGNED_BYTE_8_WIDETAG:
691             case SIMPLE_ARRAY_UNSIGNED_BYTE_15_WIDETAG:
692             case SIMPLE_ARRAY_UNSIGNED_BYTE_16_WIDETAG:
693
694             case SIMPLE_ARRAY_UNSIGNED_FIXNUM_WIDETAG:
695
696             case SIMPLE_ARRAY_UNSIGNED_BYTE_31_WIDETAG:
697             case SIMPLE_ARRAY_UNSIGNED_BYTE_32_WIDETAG:
698 #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG
699             case SIMPLE_ARRAY_UNSIGNED_BYTE_63_WIDETAG:
700 #endif
701 #ifdef SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG
702             case SIMPLE_ARRAY_UNSIGNED_BYTE_64_WIDETAG:
703 #endif
704 #ifdef SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG
705             case SIMPLE_ARRAY_SIGNED_BYTE_8_WIDETAG:
706 #endif
707 #ifdef SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG
708             case SIMPLE_ARRAY_SIGNED_BYTE_16_WIDETAG:
709 #endif
710
711             case SIMPLE_ARRAY_FIXNUM_WIDETAG:
712
713 #ifdef SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG
714             case SIMPLE_ARRAY_SIGNED_BYTE_32_WIDETAG:
715 #endif
716 #ifdef SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG
717             case SIMPLE_ARRAY_SIGNED_BYTE_64_WIDETAG:
718 #endif
719             case SIMPLE_ARRAY_SINGLE_FLOAT_WIDETAG:
720             case SIMPLE_ARRAY_DOUBLE_FLOAT_WIDETAG:
721 #ifdef SIMPLE_ARRAY_LONG_FLOAT_WIDETAG
722             case SIMPLE_ARRAY_LONG_FLOAT_WIDETAG:
723 #endif
724 #ifdef SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG
725             case SIMPLE_ARRAY_COMPLEX_SINGLE_FLOAT_WIDETAG:
726 #endif
727 #ifdef SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG
728             case SIMPLE_ARRAY_COMPLEX_DOUBLE_FLOAT_WIDETAG:
729 #endif
730 #ifdef SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG
731             case SIMPLE_ARRAY_COMPLEX_LONG_FLOAT_WIDETAG:
732 #endif
733             case COMPLEX_BASE_STRING_WIDETAG:
734 #ifdef COMPLEX_CHARACTER_STRING_WIDETAG
735         case COMPLEX_CHARACTER_STRING_WIDETAG:
736 #endif
737             case COMPLEX_VECTOR_NIL_WIDETAG:
738             case COMPLEX_BIT_VECTOR_WIDETAG:
739             case COMPLEX_VECTOR_WIDETAG:
740             case COMPLEX_ARRAY_WIDETAG:
741                 break;
742
743             case CODE_HEADER_WIDETAG:
744                 print_slots(code_slots, count-1, ptr);
745                 break;
746
747             case SIMPLE_FUN_HEADER_WIDETAG:
748                 print_slots(fn_slots, 5, ptr);
749                 break;
750
751             case RETURN_PC_HEADER_WIDETAG:
752                 print_obj("code: ", obj - (count * 4));
753                 break;
754
755             case CLOSURE_HEADER_WIDETAG:
756                 print_slots(closure_slots, count, ptr);
757                 break;
758
759             case FUNCALLABLE_INSTANCE_HEADER_WIDETAG:
760                 print_slots(funcallable_instance_slots, count, ptr);
761                 break;
762
763             case VALUE_CELL_HEADER_WIDETAG:
764                 print_slots(value_cell_slots, 1, ptr);
765                 break;
766
767             case SAP_WIDETAG:
768                 NEWLINE_OR_RETURN;
769 #ifndef LISP_FEATURE_ALPHA
770                 printf("0x%08lx", (unsigned long) *ptr);
771 #else
772                 printf("0x%016lx", *(lispobj*)(ptr+1));
773 #endif
774                 break;
775
776             case WEAK_POINTER_WIDETAG:
777                 print_slots(weak_pointer_slots, 1, ptr);
778                 break;
779
780             case CHARACTER_WIDETAG:
781             case UNBOUND_MARKER_WIDETAG:
782                 NEWLINE_OR_RETURN;
783                 printf("pointer to an immediate?");
784                 break;
785
786             case FDEFN_WIDETAG:
787                 print_slots(fdefn_slots, count, ptr);
788                 break;
789
790             default:
791                 NEWLINE_OR_RETURN;
792                 printf("Unknown header object?");
793                 break;
794         }
795     }
796 }
797
798 static void print_obj(char *prefix, lispobj obj)
799 {
800 #ifdef LISP_FEATURE_X86_64
801     static void (*verbose_fns[])(lispobj obj)
802         = {print_fixnum, print_otherimm, print_fixnum, print_struct,
803            print_fixnum, print_otherimm, print_fixnum, print_list,
804            print_fixnum, print_otherimm, print_fixnum, print_otherptr,
805            print_fixnum, print_otherimm, print_fixnum, print_otherptr};
806     static void (*brief_fns[])(lispobj obj)
807         = {brief_fixnum, brief_otherimm, brief_fixnum, brief_struct,
808            brief_fixnum, brief_otherimm, brief_fixnum, brief_list,
809            brief_fixnum, brief_otherimm, brief_fixnum, brief_otherptr,
810            brief_fixnum, brief_otherimm, brief_fixnum, brief_otherptr};
811 #else
812     static void (*verbose_fns[])(lispobj obj)
813         = {print_fixnum, print_struct, print_otherimm, print_list,
814            print_fixnum, print_otherptr, print_otherimm, print_otherptr};
815     static void (*brief_fns[])(lispobj obj)
816         = {brief_fixnum, brief_struct, brief_otherimm, brief_list,
817            brief_fixnum, brief_otherptr, brief_otherimm, brief_otherptr};
818 #endif
819     int type = lowtag_of(obj);
820     struct var *var = lookup_by_obj(obj);
821     char buffer[256];
822     boolean verbose = cur_depth < brief_depth;
823
824     if (!continue_p(verbose))
825         return;
826
827     if (var != NULL && var_clock(var) == cur_clock)
828         dont_descend = 1;
829
830     if (var == NULL && is_lisp_pointer(obj))
831         var = define_var(NULL, obj, 0);
832
833     if (var != NULL)
834         var_setclock(var, cur_clock);
835
836     cur_depth++;
837     if (verbose) {
838         if (var != NULL) {
839             sprintf(buffer, "$%s=", var_name(var));
840             newline(buffer);
841         }
842         else
843             newline(NULL);
844         printf("%s0x%08lx: ", prefix, (unsigned long) obj);
845         if (cur_depth < brief_depth) {
846             fputs(lowtag_names[type], stdout);
847             (*verbose_fns[type])(obj);
848         }
849         else
850             (*brief_fns[type])(obj);
851     }
852     else {
853         if (dont_descend)
854             printf("$%s", var_name(var));
855         else {
856             if (var != NULL)
857                 printf("$%s=", var_name(var));
858             (*brief_fns[type])(obj);
859         }
860     }
861     cur_depth--;
862     dont_descend = 0;
863 }
864
865 void reset_printer()
866 {
867     cur_clock++;
868     cur_lines = 0;
869     dont_descend = 0;
870 }
871
872 void print(lispobj obj)
873 {
874     skip_newline = 1;
875     cur_depth = 0;
876     max_depth = 5;
877     max_lines = 20;
878
879     print_obj("", obj);
880
881     putchar('\n');
882 }
883
884 void brief_print(lispobj obj)
885 {
886     skip_newline = 1;
887     cur_depth = 0;
888     max_depth = 1;
889     max_lines = 5000;
890     cur_lines = 0;
891
892     print_obj("", obj);
893     putchar('\n');
894 }
895
896 #else
897
898 void
899 brief_print(lispobj obj)
900 {
901     printf("lispobj 0x%lx\n", (unsigned long)obj);
902 }
903
904 #endif /* defined(LISP_FEATURE_SB_LDB) */