/*-1* SPDX-License-Identifier: BSD-2-Clause2*3* Copyright (c) 2007 Robert N. M. Watson4* All rights reserved.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728/*-29* Simple DDB scripting mechanism. Each script consists of a named list of30* DDB commands to execute sequentially. A more sophisticated scripting31* language might be desirable, but would be significantly more complex to32* implement. A more interesting syntax might allow general use of variables33* and extracting of useful values, such as a thread's process identifier,34* for passing into further DDB commands. Certain scripts are run35* automatically at kdb_enter(), if defined, based on how the debugger is36* entered, allowing scripted responses to panics, break signals, etc.37*38* Scripts may be managed from within DDB using the script, scripts, and39* unscript commands. They may also be managed from userspace using ddb(8),40* which operates using a set of sysctls.41*42* TODO:43* - Allow scripts to be defined using tunables so that they can be defined44* before boot and be present in single-user mode without boot scripts45* running.46* - Memory allocation is not possible from within DDB, so we use a set of47* statically allocated buffers to hold defined scripts. However, when48* scripts are being defined from userspace via sysctl, we could in fact be49* using malloc(9) and therefore not impose a static limit, giving greater50* flexibility and avoiding hard-defined buffer limits.51* - When scripts run automatically on entrance to DDB, placing "continue" at52* the end still results in being in the debugger, as we unconditionally53* run db_command_loop() after the script. There should be a way to avoid54* this.55*/5657#include <sys/param.h>58#include <sys/kdb.h>59#include <sys/kernel.h>60#include <sys/libkern.h>61#include <sys/lock.h>62#include <sys/malloc.h>63#include <sys/mutex.h>64#include <sys/sbuf.h>65#include <sys/sysctl.h>66#include <sys/systm.h>6768#include <ddb/ddb.h>69#include <ddb/db_command.h>70#include <ddb/db_lex.h>7172#include <machine/setjmp.h>7374/*75* struct ddb_script describes an individual script.76*/77struct ddb_script {78char ds_scriptname[DB_MAXSCRIPTNAME];79char ds_script[DB_MAXSCRIPTLEN];80};8182/*83* Global list of scripts -- defined scripts have non-empty name fields.84*/85static struct ddb_script db_script_table[DB_MAXSCRIPTS];8687/*88* While executing a script, we parse it using strsep(), so require a89* temporary buffer that may be used destructively. Since we support weak90* recursion of scripts (one may reference another), we need one buffer for91* each concurrently executing script.92*/93static struct db_recursion_data {94char drd_buffer[DB_MAXSCRIPTLEN];95} db_recursion_data[DB_MAXSCRIPTRECURSION];96static int db_recursion = -1;9798/*99* We use a separate static buffer for script validation so that it is safe100* to validate scripts from within a script. This is used only in101* db_script_valid(), which should never be called reentrantly.102*/103static char db_static_buffer[DB_MAXSCRIPTLEN];104105/*106* Synchronization is not required from within the debugger, as it is107* singe-threaded (although reentrance must be carefully considered).108* However, it is required when interacting with scripts from user space109* processes. Sysctl procedures acquire db_script_mtx before accessing the110* global script data structures.111*/112static struct mtx db_script_mtx;113MTX_SYSINIT(db_script_mtx, &db_script_mtx, "db_script_mtx", MTX_DEF);114115/*116* Some script names have special meaning, such as those executed117* automatically when KDB is entered.118*/119#define DB_SCRIPT_KDBENTER_PREFIX "kdb.enter" /* KDB has entered. */120#define DB_SCRIPT_KDBENTER_DEFAULT "kdb.enter.default"121122/*123* Find the existing script slot for a named script, if any.124*/125static struct ddb_script *126db_script_lookup(const char *scriptname)127{128int i;129130for (i = 0; i < DB_MAXSCRIPTS; i++) {131if (strcmp(db_script_table[i].ds_scriptname, scriptname) ==1320)133return (&db_script_table[i]);134}135return (NULL);136}137138/*139* Find a new slot for a script, if available. Does not mark as allocated in140* any way--this must be done by the caller.141*/142static struct ddb_script *143db_script_new(void)144{145int i;146147for (i = 0; i < DB_MAXSCRIPTS; i++) {148if (strlen(db_script_table[i].ds_scriptname) == 0)149return (&db_script_table[i]);150}151return (NULL);152}153154/*155* Perform very rudimentary validation of a proposed script. It would be156* easy to imagine something more comprehensive. The script string is157* validated in a static buffer.158*/159static int160db_script_valid(const char *scriptname, const char *script)161{162char *buffer, *command;163164if (strlen(scriptname) == 0)165return (EINVAL);166if (strlen(scriptname) >= DB_MAXSCRIPTNAME)167return (EINVAL);168if (strlen(script) >= DB_MAXSCRIPTLEN)169return (EINVAL);170buffer = db_static_buffer;171strcpy(buffer, script);172while ((command = strsep(&buffer, ";")) != NULL) {173if (strlen(command) >= DB_MAXLINE)174return (EINVAL);175}176return (0);177}178179/*180* Modify an existing script or add a new script with the specified script181* name and contents. If there are no script slots available, an error will182* be returned.183*/184static int185db_script_set(const char *scriptname, const char *script)186{187struct ddb_script *dsp;188int error;189190error = db_script_valid(scriptname, script);191if (error)192return (error);193dsp = db_script_lookup(scriptname);194if (dsp == NULL) {195dsp = db_script_new();196if (dsp == NULL)197return (ENOSPC);198strlcpy(dsp->ds_scriptname, scriptname,199sizeof(dsp->ds_scriptname));200}201strlcpy(dsp->ds_script, script, sizeof(dsp->ds_script));202return (0);203}204205/*206* Delete an existing script by name, if found.207*/208static int209db_script_unset(const char *scriptname)210{211struct ddb_script *dsp;212213dsp = db_script_lookup(scriptname);214if (dsp == NULL)215return (ENOENT);216strcpy(dsp->ds_scriptname, "");217strcpy(dsp->ds_script, "");218return (0);219}220221/*222* Trim leading/trailing white space in a command so that we don't pass223* carriage returns, etc, into DDB command parser.224*/225static int226db_command_trimmable(char ch)227{228229switch (ch) {230case ' ':231case '\t':232case '\n':233case '\r':234return (1);235236default:237return (0);238}239}240241static void242db_command_trim(char **commandp)243{244char *command;245246command = *commandp;247while (db_command_trimmable(*command))248command++;249while ((strlen(command) > 0) &&250db_command_trimmable(command[strlen(command) - 1]))251command[strlen(command) - 1] = 0;252*commandp = command;253}254255/*256* Execute a script, breaking it up into individual commands and passing them257* sequentially into DDB's input processing. Use the KDB jump buffer to258* restore control to the main script loop if things get too wonky when259* processing a command -- i.e., traps, etc. Also, make sure we don't exceed260* practical limits on recursion.261*262* XXXRW: If any individual command is too long, it will be truncated when263* injected into the input at a lower layer. We should validate the script264* before configuring it to avoid this scenario.265*/266static int267db_script_exec(const char *scriptname, int warnifnotfound)268{269struct db_recursion_data *drd;270struct ddb_script *dsp;271char *buffer, *command;272void *prev_jb;273jmp_buf jb;274275dsp = db_script_lookup(scriptname);276if (dsp == NULL) {277if (warnifnotfound)278db_printf("script '%s' not found\n", scriptname);279return (ENOENT);280}281282if (db_recursion >= DB_MAXSCRIPTRECURSION) {283db_printf("Script stack too deep\n");284return (E2BIG);285}286db_recursion++;287drd = &db_recursion_data[db_recursion];288289/*290* Parse script in temporary buffer, since strsep() is destructive.291*/292buffer = drd->drd_buffer;293strcpy(buffer, dsp->ds_script);294while ((command = strsep(&buffer, ";")) != NULL) {295db_printf("db:%d:%s> %s\n", db_recursion, dsp->ds_scriptname,296command);297db_command_trim(&command);298prev_jb = kdb_jmpbuf(jb);299if (setjmp(jb) == 0)300db_command_script(command);301else302db_printf("Script command '%s' returned error\n",303command);304kdb_jmpbuf(prev_jb);305}306db_recursion--;307return (0);308}309310/*311* Wrapper for exec path that is called on KDB enter. Map reason for KDB312* enter to a script name, and don't whine if the script doesn't exist. If313* there is no matching script, try the catch-all script.314*/315void316db_script_kdbenter(const char *eventname)317{318char scriptname[DB_MAXSCRIPTNAME];319320snprintf(scriptname, sizeof(scriptname), "%s.%s",321DB_SCRIPT_KDBENTER_PREFIX, eventname);322if (db_script_exec(scriptname, 0) == ENOENT)323(void)db_script_exec(DB_SCRIPT_KDBENTER_DEFAULT, 0);324}325326/*-327* DDB commands for scripting, as reached via the DDB user interface:328*329* scripts - lists scripts330* run <scriptname> - run a script331* script <scriptname> - prints script332* script <scriptname> <script> - set a script333* unscript <scriptname> - remove a script334*/335336/*337* List scripts and their contents.338*/339void340db_scripts_cmd(db_expr_t addr, bool have_addr, db_expr_t count,341char *modif)342{343int i;344345for (i = 0; i < DB_MAXSCRIPTS; i++) {346if (strlen(db_script_table[i].ds_scriptname) != 0) {347db_printf("%s=%s\n",348db_script_table[i].ds_scriptname,349db_script_table[i].ds_script);350}351}352}353354/*355* Execute a script.356*/357void358db_run_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)359{360int t;361362/*363* Right now, we accept exactly one argument. In the future, we364* might want to accept flags and arguments to the script itself.365*/366t = db_read_token();367if (t != tIDENT)368db_error("?\n");369370if (db_read_token() != tEOL)371db_error("?\n");372373db_script_exec(db_tok_string, 1);374}375376/*377* Print or set a named script, with the set portion broken out into its own378* function. We must directly access the remainder of the DDB line input as379* we do not wish to use db_lex's token processing.380*/381void382db_script_cmd(db_expr_t addr, bool have_addr, db_expr_t count,383char *modif)384{385char *buf, scriptname[DB_MAXSCRIPTNAME];386struct ddb_script *dsp;387int error, t;388389t = db_read_token();390if (t != tIDENT) {391db_printf("usage: script scriptname=script\n");392db_skip_to_eol();393return;394}395396if (strlcpy(scriptname, db_tok_string, sizeof(scriptname)) >=397sizeof(scriptname)) {398db_printf("scriptname too long\n");399db_skip_to_eol();400return;401}402403t = db_read_token();404if (t == tEOL) {405dsp = db_script_lookup(scriptname);406if (dsp == NULL) {407db_printf("script '%s' not found\n", scriptname);408db_skip_to_eol();409return;410}411db_printf("%s=%s\n", scriptname, dsp->ds_script);412} else if (t == tEQ) {413buf = db_get_line();414if (buf[strlen(buf)-1] == '\n')415buf[strlen(buf)-1] = '\0';416error = db_script_set(scriptname, buf);417if (error != 0)418db_printf("Error: %d\n", error);419} else420db_printf("?\n");421db_skip_to_eol();422}423424/*425* Remove a named script.426*/427void428db_unscript_cmd(db_expr_t addr, bool have_addr, db_expr_t count,429char *modif)430{431int error, t;432433t = db_read_token();434if (t != tIDENT) {435db_printf("?\n");436db_skip_to_eol();437return;438}439440error = db_script_unset(db_tok_string);441if (error == ENOENT) {442db_printf("script '%s' not found\n", db_tok_string);443db_skip_to_eol();444return;445}446db_skip_to_eol();447}448449/*450* Sysctls for managing DDB scripting:451*452* debug.ddb.scripting.script - Define a new script453* debug.ddb.scripting.scripts - List of names *and* scripts454* debug.ddb.scripting.unscript - Remove an existing script455*456* Since we don't want to try to manage arbitrary extensions to the sysctl457* name space from the debugger, the script/unscript sysctls are a bit more458* like RPCs and a bit less like normal get/set requests. The ddb(8) command459* line tool wraps them to make things a bit more user-friendly.460*/461static SYSCTL_NODE(_debug_ddb, OID_AUTO, scripting,462CTLFLAG_RW | CTLFLAG_MPSAFE, 0,463"DDB script settings");464465static int466sysctl_debug_ddb_scripting_scripts(SYSCTL_HANDLER_ARGS)467{468struct sbuf sb;469int error, i, len;470char *buffer;471472/*473* Make space to include a maximum-length name, = symbol,474* maximum-length script, and carriage return for every script that475* may be defined.476*/477len = DB_MAXSCRIPTS * (DB_MAXSCRIPTNAME + 1 + DB_MAXSCRIPTLEN + 1);478buffer = malloc(len, M_TEMP, M_WAITOK);479(void)sbuf_new(&sb, buffer, len, SBUF_FIXEDLEN);480mtx_lock(&db_script_mtx);481for (i = 0; i < DB_MAXSCRIPTS; i++) {482if (strlen(db_script_table[i].ds_scriptname) == 0)483continue;484(void)sbuf_printf(&sb, "%s=%s\n",485db_script_table[i].ds_scriptname,486db_script_table[i].ds_script);487}488mtx_unlock(&db_script_mtx);489sbuf_finish(&sb);490error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb) + 1);491sbuf_delete(&sb);492free(buffer, M_TEMP);493return (error);494}495SYSCTL_PROC(_debug_ddb_scripting, OID_AUTO, scripts,496CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0,497sysctl_debug_ddb_scripting_scripts, "A",498"List of defined scripts");499500static int501sysctl_debug_ddb_scripting_script(SYSCTL_HANDLER_ARGS)502{503char *buffer, *script, *scriptname;504int error, len;505506/*507* Maximum length for an input string is DB_MAXSCRIPTNAME + '='508* symbol + DB_MAXSCRIPT.509*/510len = DB_MAXSCRIPTNAME + DB_MAXSCRIPTLEN + 1;511buffer = malloc(len, M_TEMP, M_WAITOK | M_ZERO);512error = sysctl_handle_string(oidp, buffer, len, req);513if (error)514goto out;515516/*517* Argument will be in form scriptname=script, so split into the518* scriptname and script.519*/520script = buffer;521scriptname = strsep(&script, "=");522if (script == NULL) {523error = EINVAL;524goto out;525}526mtx_lock(&db_script_mtx);527error = db_script_set(scriptname, script);528mtx_unlock(&db_script_mtx);529out:530free(buffer, M_TEMP);531return (error);532}533SYSCTL_PROC(_debug_ddb_scripting, OID_AUTO, script,534CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0,535sysctl_debug_ddb_scripting_script, "A",536"Set a script");537538/*539* debug.ddb.scripting.unscript has somewhat unusual sysctl semantics -- set540* the name of the script that you want to delete.541*/542static int543sysctl_debug_ddb_scripting_unscript(SYSCTL_HANDLER_ARGS)544{545char name[DB_MAXSCRIPTNAME];546int error;547548bzero(name, sizeof(name));549error = sysctl_handle_string(oidp, name, sizeof(name), req);550if (error)551return (error);552if (req->newptr == NULL)553return (0);554mtx_lock(&db_script_mtx);555error = db_script_unset(name);556mtx_unlock(&db_script_mtx);557if (error == ENOENT)558return (EINVAL); /* Don't confuse sysctl consumers. */559return (0);560}561SYSCTL_PROC(_debug_ddb_scripting, OID_AUTO, unscript,562CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 0,563sysctl_debug_ddb_scripting_unscript, "A",564"Unset a script");565566567