174429Sorion/* $OpenBSD: db_output.c,v 1.37 2021/06/10 12:33:48 bluhm Exp $ */ 274429Sorion/* $NetBSD: db_output.c,v 1.13 1996/04/01 17:27:14 christos Exp $ */ 374429Sorion 474429Sorion/* 574429Sorion * Mach Operating System 674429Sorion * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University 774429Sorion * All Rights Reserved. 874429Sorion * 974429Sorion * Permission to use, copy, modify and distribute this software and its 1074429Sorion * documentation is hereby granted, provided that both the copyright 1174429Sorion * notice and this permission notice appear in all copies of the 1274429Sorion * software, derivative works or modified versions, and any portions 1374429Sorion * thereof, and that both notices appear in supporting documentation. 1474429Sorion * 1574429Sorion * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 1674429Sorion * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 1774429Sorion * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1874429Sorion * 1974429Sorion * Carnegie Mellon requests users of this software to return to 2074429Sorion * 2174429Sorion * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2274429Sorion * School of Computer Science 2374429Sorion * Carnegie Mellon University 2474429Sorion * Pittsburgh PA 15213-3890 2574429Sorion * 2674429Sorion * any improvements or extensions that they make and grant Carnegie Mellon 2774429Sorion * the rights to redistribute these changes. 2874429Sorion */ 2974429Sorion 3074429Sorion/* 3174429Sorion * Printf and character output for debugger. 3274429Sorion */ 3374429Sorion#include <sys/param.h> 3474429Sorion#include <sys/atomic.h> 3574429Sorion#include <sys/stdarg.h> 3674429Sorion#include <sys/systm.h> 3774429Sorion#include <sys/stacktrace.h> 3874429Sorion 3974429Sorion#include <dev/cons.h> 4074429Sorion 4174429Sorion#include <machine/db_machdep.h> 4274429Sorion 4374429Sorion#include <ddb/db_command.h> 4474429Sorion#include <ddb/db_output.h> 4574429Sorion#include <ddb/db_access.h> 4674429Sorion#include <ddb/db_interface.h> 4774429Sorion#include <ddb/db_sym.h> 4874429Sorion#include <ddb/db_var.h> 4974429Sorion 5074429Sorion/* 5174429Sorion * Character output - tracks position in line. 5274429Sorion * To do this correctly, we should know how wide 5374429Sorion * the output device is - then we could zero 5474429Sorion * the line position when the output device wraps 5574429Sorion * around to the start of the next line. 5674429Sorion * 5774429Sorion * Instead, we count the number of spaces printed 5874429Sorion * since the last printing character so that we 5974429Sorion * don't print trailing spaces. This avoids most 6074429Sorion * of the wraparounds. 6174429Sorion */ 6274429Sorion 6374429Sorion#ifndef DB_MAX_LINE 6474429Sorion#define DB_MAX_LINE 24 /* maximum line */ 6574429Sorion#define DB_MAX_WIDTH 80 /* maximum width */ 6674429Sorion#endif /* DB_MAX_LINE */ 6774429Sorion 6874429Sorion#define DB_MIN_MAX_WIDTH 20 /* minimum max width */ 6974429Sorion#define DB_MIN_MAX_LINE 3 /* minimum max line */ 7074429Sorion#define CTRL(c) ((c) & 0xff) 7174429Sorion 7274429Sorionint db_output_position = 0; /* output column */ 7374429Sorionint db_output_line = 0; /* output line number */ 7474429Sorionint db_last_non_space = 0; /* last non-space character */ 7574429Sorionint db_tab_stop_width = 8; /* how wide are tab stops? */ 7674429Sorion#define NEXT_TAB(i) \ 7774429Sorion ((((i) + db_tab_stop_width) / db_tab_stop_width) * db_tab_stop_width) 7874429Sorionint db_max_line = DB_MAX_LINE; /* output max lines */ 7974429Sorionint db_max_width = DB_MAX_WIDTH; /* output line width */ 8074429Sorionint db_radix = 16; /* output numbers radix */ 8174429Sorion 8274429Sorionstatic void db_more(void); 8374429Sorion 8474429Sorion/* 8574429Sorion * Force pending whitespace. 8674429Sorion */ 8774429Sorionvoid 8874429Soriondb_force_whitespace(void) 8974429Sorion{ 9074429Sorion int last_print, next_tab; 9174429Sorion 9274429Sorion last_print = db_last_non_space; 9374429Sorion while (last_print < db_output_position) { 9474429Sorion next_tab = NEXT_TAB(last_print); 9574429Sorion if (next_tab <= db_output_position) { 9674429Sorion while (last_print < next_tab) { /* DON'T send a tab!!! */ 9774429Sorion cnputc(' '); 9874429Sorion last_print++; 9974429Sorion } 10074429Sorion } else { 10174429Sorion cnputc(' '); 10274429Sorion last_print++; 10374429Sorion } 10474429Sorion } 10574429Sorion db_last_non_space = db_output_position; 10674429Sorion} 10774429Sorion 10874429Sorionstatic void 10974429Soriondb_more(void) 11074429Sorion{ 11174429Sorion char *p; 11274429Sorion int quit_output = 0; 11374429Sorion 11474429Sorion for (p = "--db_more--"; *p; p++) 11574429Sorion cnputc(*p); 11674429Sorion switch(cngetc()) { 11774429Sorion case ' ': 11874429Sorion db_output_line = 0; 11974429Sorion break; 12074429Sorion case 'q': 12174429Sorion case CTRL('c'): 12274429Sorion db_output_line = 0; 12374429Sorion quit_output = 1; 12474429Sorion break; 12574429Sorion default: 12674429Sorion db_output_line--; 12774429Sorion break; 12874429Sorion } 12974429Sorion p = "\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b"; 13074429Sorion while (*p) 13174429Sorion cnputc(*p++); 13274429Sorion if (quit_output) { 13374429Sorion db_error(0); 13474429Sorion /* NOTREACHED */ 13574429Sorion } 13674429Sorion} 13774429Sorion 13874429Sorion/* 13974429Sorion * Output character. Buffer whitespace. 14074429Sorion */ 14174429Sorionvoid 14274429Soriondb_putchar(int c) 14374429Sorion{ 14474429Sorion if (db_max_line >= DB_MIN_MAX_LINE && db_output_line >= db_max_line-1) 14574429Sorion db_more(); 14674429Sorion 14774429Sorion if (c > ' ' && c <= '~') { 14874429Sorion /* 14974429Sorion * Printing character. 15074429Sorion * If we have spaces to print, print them first. 15174429Sorion * Use tabs if possible. 15274429Sorion */ 15374429Sorion db_force_whitespace(); 15474429Sorion cnputc(c); 15574429Sorion db_output_position++; 15674429Sorion if (db_max_width >= DB_MIN_MAX_WIDTH && 15774429Sorion db_output_position >= db_max_width-1) { 15874429Sorion /* auto new line */ 15974429Sorion cnputc('\n'); 16074429Sorion db_output_position = 0; 16174429Sorion db_last_non_space = 0; 16274429Sorion db_output_line++; 16374429Sorion } 16474429Sorion db_last_non_space = db_output_position; 16574429Sorion } else if (c == '\n') { 16674429Sorion /* Return */ 16774429Sorion cnputc(c); 16874429Sorion db_output_position = 0; 16974429Sorion db_last_non_space = 0; 17074429Sorion db_output_line++; 17174429Sorion } else if (c == '\t') { 17274429Sorion /* assume tabs every 8 positions */ 17374429Sorion db_output_position = NEXT_TAB(db_output_position); 17474429Sorion } else if (c == ' ') { 17574429Sorion /* space */ 17674429Sorion db_output_position++; 17774429Sorion } else if (c == '\007') { 17874429Sorion /* bell */ 17974429Sorion cnputc(c); 18074429Sorion } 18174429Sorion /* other characters are assumed non-printing */ 18274429Sorion} 18374429Sorion 18474429Sorion/* 18574429Sorion * Return output position 18674429Sorion */ 18774429Sorionint 18874429Soriondb_print_position(void) 18974429Sorion{ 19074429Sorion return (db_output_position); 19174429Sorion} 19274429Sorion 19374429Sorion/* 19474429Sorion * End line if too long. 19574429Sorion */ 19674429Sorionvoid 19774429Soriondb_end_line(int space) 19874429Sorion{ 19974429Sorion if (db_output_position >= db_max_width - space) 20074429Sorion db_printf("\n"); 20174429Sorion} 20274429Sorion 20374429Sorionchar * 20474429Soriondb_format(char *buf, size_t bufsize, long val, int format, int alt, int width) 20574429Sorion{ 20674429Sorion const char *fmt; 20774429Sorion 20874429Sorion if (format == DB_FORMAT_Z || db_radix == 16) 20974429Sorion fmt = alt ? "-%#*lx" : "-%*lx"; 21074429Sorion else if (db_radix == 8) 21174429Sorion fmt = alt ? "-%#*lo" : "-%*lo"; 21274429Sorion else 21374429Sorion fmt = alt ? "-%#*lu" : "-%*lu"; 21474429Sorion 21574429Sorion /* The leading '-' is a nasty (and beautiful) idea from NetBSD */ 21674429Sorion if (val < 0 && format != DB_FORMAT_N) 21774429Sorion val = -val; 21874429Sorion else 21974429Sorion fmt++; 22074429Sorion 22174429Sorion snprintf(buf, bufsize, fmt, width, val); 22274429Sorion return (buf); 22374429Sorion} 22474429Sorion 22574429Sorionvoid 22674429Soriondb_stack_dump(void) 22774429Sorion{ 22874429Sorion static struct cpu_info *intrace = NULL; 22974429Sorion struct cpu_info *tracing, *ci = curcpu(); 23074429Sorion 23174429Sorion tracing = atomic_cas_ptr(&intrace, NULL, ci); 23274429Sorion if (tracing != NULL) { 23374429Sorion if (tracing == ci) 23474429Sorion printf("Faulted in traceback, aborting...\n"); 23574429Sorion else 23674429Sorion printf("Parallel traceback, suppressed...\n"); 23774429Sorion return; 23874429Sorion } 23974429Sorion 24074429Sorion printf("Starting stack trace...\n"); 24174429Sorion db_stack_trace_print((db_expr_t)__builtin_frame_address(0), 1, 24274429Sorion 256 /* low limit */, "", printf); 24374429Sorion printf("End of stack trace.\n"); 24474429Sorion membar_producer(); 24574429Sorion intrace = NULL; 24674429Sorion} 24774429Sorion 24874429Sorionvoid 24974429Sorionstacktrace_print(struct stacktrace *st, int (*pr)(const char *, ...)) 25074429Sorion{ 25174429Sorion unsigned int i; 25274429Sorion 25374429Sorion for (i = 0; i < st->st_count; i++) { 25474429Sorion (*pr)("#%-2u ", i); 25574429Sorion db_printsym(st->st_pc[i], DB_STGY_PROC, pr); 25674429Sorion (*pr)("\n"); 25774429Sorion } 25874429Sorion if (st->st_count == 0) 25974429Sorion (*pr)("<empty stack trace>\n"); 26074429Sorion} 26174429Sorion 26274429Sorionvoid 26374429Soriondb_resize(int cols, int rows) 26474429Sorion{ 26574429Sorion db_max_width = cols; 26674429Sorion db_max_line = rows; 26774429Sorion} 26874429Sorion