gdb_cons.c revision 283291
1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2006 Sam Leffler 3177633Sdfr * All rights reserved. 4177633Sdfr * 5177633Sdfr * Redistribution and use in source and binary forms, with or without 6177633Sdfr * modification, are permitted provided that the following conditions 7177633Sdfr * are met: 8177633Sdfr * 9177633Sdfr * 1. Redistributions of source code must retain the above copyright 10177633Sdfr * notice, this list of conditions and the following disclaimer. 11177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12177633Sdfr * notice, this list of conditions and the following disclaimer in the 13177633Sdfr * documentation and/or other materials provided with the distribution. 14177633Sdfr * 15177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16177633Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17177633Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18177633Sdfr * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19177633Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20177633Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21177633Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22177633Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23177633Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24177633Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25177633Sdfr */ 26177633Sdfr 27177633Sdfr/* 28177633Sdfr * Support for redirecting console msgs to gdb. We register 29177633Sdfr * a pseudo console to hook cnputc and send stuff to the gdb 30177633Sdfr * port. The only trickiness here is buffering output so this 31177633Sdfr * isn't dog slow. 32177633Sdfr */ 33177633Sdfr 34177633Sdfr#include <sys/cdefs.h> 35177633Sdfr__FBSDID("$FreeBSD: head/sys/gdb/gdb_cons.c 283291 2015-05-22 17:05:21Z jkim $"); 36177633Sdfr 37177633Sdfr#include <sys/param.h> 38177633Sdfr#include <sys/systm.h> 39177633Sdfr#include <sys/cons.h> 40177633Sdfr#include <sys/kdb.h> 41177633Sdfr#include <sys/kernel.h> 42177633Sdfr#include <sys/malloc.h> 43177633Sdfr#include <sys/reboot.h> 44177633Sdfr#include <sys/sysctl.h> 45177685Sdfr 46177633Sdfr#include <machine/gdb_machdep.h> 47177633Sdfr#include <machine/kdb.h> 48177633Sdfr 49177633Sdfr#include <gdb/gdb.h> 50177633Sdfr#include <gdb/gdb_int.h> 51177633Sdfr 52177633Sdfrstruct gdbcons { 53177633Sdfr int npending; 54177633Sdfr /* /2 for hex conversion, -6 for protocol glue */ 55177633Sdfr char buf[GDB_BUFSZ/2 - 6]; 56177633Sdfr struct callout flush; 57177633Sdfr}; 58177633Sdfrstatic struct gdbcons state = { -1 }; 59177633Sdfr 60177633Sdfrstatic int gdbcons_enable = 0; 61177633SdfrSYSCTL_INT(_debug, OID_AUTO, gdbcons, CTLFLAG_RWTUN, &gdbcons_enable, 62177633Sdfr 0, "copy console messages to GDB"); 63177633Sdfr 64177633Sdfrstatic void 65177633Sdfrgdb_cnprobe(struct consdev *cp) 66177633Sdfr{ 67177633Sdfr sprintf(cp->cn_name, "gdb"); 68177633Sdfr cp->cn_pri = CN_LOW; /* XXX no way to say "write only" */ 69177633Sdfr} 70177633Sdfr 71177633Sdfrstatic void 72177633Sdfrgdb_cninit(struct consdev *cp) 73177633Sdfr{ 74177633Sdfr struct gdbcons *c = &state; 75177633Sdfr 76177633Sdfr /* setup tx buffer and callout */ 77177633Sdfr if (c->npending == -1) { 78177633Sdfr c->npending = 0; 79177633Sdfr callout_init(&c->flush, 1); 80177633Sdfr cp->cn_arg = c; 81177633Sdfr } 82177633Sdfr} 83177633Sdfr 84177633Sdfrstatic void 85177633Sdfrgdb_cnterm(struct consdev *cp) 86177633Sdfr{ 87177633Sdfr} 88177633Sdfr 89177633Sdfrstatic void 90177633Sdfrgdb_cngrab(struct consdev *cp) 91177633Sdfr{ 92177633Sdfr} 93177633Sdfr 94177633Sdfrstatic void 95177633Sdfrgdb_cnungrab(struct consdev *cp) 96177633Sdfr{ 97177633Sdfr} 98177633Sdfr 99177633Sdfrstatic int 100177633Sdfrgdb_cngetc(struct consdev *cp) 101177633Sdfr{ 102177633Sdfr return -1; 103177633Sdfr} 104177633Sdfr 105177633Sdfrstatic void 106177633Sdfrgdb_tx_puthex(int c) 107177633Sdfr{ 108177633Sdfr const char *hex = "0123456789abcdef"; 109177633Sdfr 110177633Sdfr gdb_tx_char(hex[(c>>4)&0xf]); 111177633Sdfr gdb_tx_char(hex[(c>>0)&0xf]); 112177633Sdfr} 113177633Sdfr 114177633Sdfrstatic void 115177633Sdfrgdb_cnflush(void *arg) 116177633Sdfr{ 117177633Sdfr struct gdbcons *gc = arg; 118177633Sdfr int i; 119177633Sdfr 120177633Sdfr gdb_tx_begin('O'); 121177633Sdfr for (i = 0; i < gc->npending; i++) 122177633Sdfr gdb_tx_puthex(gc->buf[i]); 123177633Sdfr gdb_tx_end(); 124177633Sdfr gc->npending = 0; 125177633Sdfr} 126177633Sdfr 127177633Sdfr/* 128177633Sdfr * This glop is to figure out when it's safe to use callouts 129177633Sdfr * to defer buffer flushing. There's probably a better way 130177633Sdfr * and/or an earlier point in the boot process when it's ok. 131177633Sdfr */ 132177633Sdfrstatic int calloutok = 0; 133177633Sdfrstatic void 134177633Sdfroktousecallout(void *data __unused) 135177633Sdfr{ 136177633Sdfr calloutok = 1; 137177633Sdfr} 138177633SdfrSYSINIT(gdbhack, SI_SUB_LAST, SI_ORDER_MIDDLE, oktousecallout, NULL); 139177633Sdfr 140177633Sdfrstatic void 141177633Sdfrgdb_cnputc(struct consdev *cp, int c) 142178112Sdfr{ 143178112Sdfr struct gdbcons *gc; 144178112Sdfr 145177633Sdfr if (gdbcons_enable && gdb_cur != NULL && gdb_listening) { 146177633Sdfr gc = cp->cn_arg; 147177633Sdfr if (gc->npending != 0) { 148177633Sdfr /* 149177633Sdfr * Cancel any pending callout and flush the 150177633Sdfr * buffer if there's no space for this byte. 151177633Sdfr */ 152177633Sdfr if (calloutok) 153177633Sdfr callout_stop(&gc->flush); 154177633Sdfr if (gc->npending == sizeof(gc->buf)) 155177633Sdfr gdb_cnflush(gc); 156177633Sdfr } 157177633Sdfr gc->buf[gc->npending++] = c; 158177633Sdfr /* 159177633Sdfr * Flush on end of line; this is especially helpful 160177633Sdfr * during boot when we don't have callouts to flush 161177633Sdfr * the buffer. Otherwise we defer flushing; a 1/4 162177633Sdfr * second is a guess. 163177633Sdfr */ 164177633Sdfr if (c == '\n') 165177633Sdfr gdb_cnflush(gc); 166177633Sdfr else if (calloutok) 167177633Sdfr callout_reset(&gc->flush, hz/4, gdb_cnflush, gc); 168177633Sdfr } 169178112Sdfr} 170178112Sdfr 171178112SdfrCONSOLE_DRIVER(gdb); 172178112Sdfr 173178112Sdfr/* 174177633Sdfr * Our console device only gets attached if the system is booted 175177633Sdfr * with RB_MULTIPLE set so gdb_init also calls us to attach the 176177633Sdfr * console so we're setup regardless. 177177633Sdfr */ 178177633Sdfrvoid 179177633Sdfrgdb_consinit(void) 180177633Sdfr{ 181177633Sdfr gdb_cnprobe(&gdb_consdev); 182177633Sdfr gdb_cninit(&gdb_consdev); 183177633Sdfr cnadd(&gdb_consdev); 184177633Sdfr} 185177633Sdfr