15dfecf96Smrg/* 25dfecf96Smrg * Copyright (c) 2001 by The XFree86 Project, Inc. 35dfecf96Smrg * 45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg * copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg * to deal in the Software without restriction, including without limitation 75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg * Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg * 115dfecf96Smrg * The above copyright notice and this permission notice shall be included in 125dfecf96Smrg * all copies or substantial portions of the Software. 135dfecf96Smrg * 145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg * SOFTWARE. 215dfecf96Smrg * 225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg * dealings in this Software without prior written authorization from the 255dfecf96Smrg * XFree86 Project. 265dfecf96Smrg * 275dfecf96Smrg * Author: Paulo César Pereira de Andrade 285dfecf96Smrg */ 295dfecf96Smrg 305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/debugger.c,v 1.24tsi Exp $ */ 315dfecf96Smrg 325dfecf96Smrg#include <ctype.h> 335dfecf96Smrg#include "lisp/io.h" 345dfecf96Smrg#include "lisp/debugger.h" 355dfecf96Smrg#include "lisp/write.h" 365dfecf96Smrg 375dfecf96Smrg#ifdef DEBUGGER 385dfecf96Smrg#define DebuggerHelp 0 395dfecf96Smrg#define DebuggerAbort 1 405dfecf96Smrg#define DebuggerBacktrace 2 415dfecf96Smrg#define DebuggerContinue 3 425dfecf96Smrg#define DebuggerFinish 4 435dfecf96Smrg#define DebuggerFrame 5 445dfecf96Smrg#define DebuggerNext 6 455dfecf96Smrg#define DebuggerPrint 7 465dfecf96Smrg#define DebuggerStep 8 475dfecf96Smrg#define DebuggerBreak 9 485dfecf96Smrg#define DebuggerDelete 10 495dfecf96Smrg#define DebuggerDown 11 505dfecf96Smrg#define DebuggerUp 12 515dfecf96Smrg#define DebuggerInfo 13 525dfecf96Smrg#define DebuggerWatch 14 535dfecf96Smrg 545dfecf96Smrg#define DebuggerInfoBreakpoints 0 555dfecf96Smrg#define DebuggerInfoBacktrace 1 565dfecf96Smrg 575dfecf96Smrg/* 585dfecf96Smrg * Prototypes 595dfecf96Smrg */ 605dfecf96Smrgstatic char *format_integer(int); 615dfecf96Smrgstatic void LispDebuggerCommand(LispObj *obj); 625dfecf96Smrg 635dfecf96Smrg/* 645dfecf96Smrg * Initialization 655dfecf96Smrg */ 665dfecf96Smrgstatic struct { 67f765521fSmrg const char *name; 685dfecf96Smrg int action; 69f765521fSmrg} const commands[] = { 705dfecf96Smrg {"help", DebuggerHelp}, 715dfecf96Smrg {"abort", DebuggerAbort}, 725dfecf96Smrg {"backtrace", DebuggerBacktrace}, 735dfecf96Smrg {"b", DebuggerBreak}, 745dfecf96Smrg {"break", DebuggerBreak}, 755dfecf96Smrg {"bt", DebuggerBacktrace}, 765dfecf96Smrg {"continue", DebuggerContinue}, 775dfecf96Smrg {"d", DebuggerDelete}, 785dfecf96Smrg {"delete", DebuggerDelete}, 795dfecf96Smrg {"down", DebuggerDown}, 805dfecf96Smrg {"finish", DebuggerFinish}, 815dfecf96Smrg {"frame", DebuggerFrame}, 825dfecf96Smrg {"info", DebuggerInfo}, 835dfecf96Smrg {"n", DebuggerNext}, 845dfecf96Smrg {"next", DebuggerNext}, 855dfecf96Smrg {"print", DebuggerPrint}, 865dfecf96Smrg {"run", DebuggerContinue}, 875dfecf96Smrg {"s", DebuggerStep}, 885dfecf96Smrg {"step", DebuggerStep}, 895dfecf96Smrg {"up", DebuggerUp}, 905dfecf96Smrg {"watch", DebuggerWatch}, 915dfecf96Smrg}; 925dfecf96Smrg 935dfecf96Smrgstatic struct { 94f765521fSmrg const char *name; 955dfecf96Smrg int subaction; 96f765521fSmrg} const info_commands[] = { 975dfecf96Smrg {"breakpoints", DebuggerInfoBreakpoints}, 985dfecf96Smrg {"stack", DebuggerInfoBacktrace}, 995dfecf96Smrg {"watchpoints", DebuggerInfoBreakpoints}, 1005dfecf96Smrg}; 1015dfecf96Smrg 102f765521fSmrgstatic const char *debugger_help = 1035dfecf96Smrg"Available commands are:\n\ 1045dfecf96Smrg\n\ 1055dfecf96Smrghelp - This message.\n\ 1065dfecf96Smrgabort - Abort the current execution, and return to toplevel.\n\ 1075dfecf96Smrgbacktrace, bt - Print backtrace.\n\ 1085dfecf96Smrgb, break - Set breakpoint at function name argument.\n\ 1095dfecf96Smrgcontinue - Continue execution.\n\ 1105dfecf96Smrgd, delete - Delete breakpoint(s), all breakpoint if no arguments given.\n\ 1115dfecf96Smrgdown - Set environment to frame called by the current one.\n\ 1125dfecf96Smrgfinish - Executes until current form is finished.\n\ 1135dfecf96Smrgframe - Set environment to selected frame.\n\ 1145dfecf96Smrginfo - Prints information about the debugger state.\n\ 1155dfecf96Smrgn, next - Evaluate next form.\n\ 1165dfecf96Smrgprint - Print value of variable name argument.\n\ 1175dfecf96Smrgrun - Continue execution.\n\ 1185dfecf96Smrgs, step - Evaluate next form, stopping on any subforms.\n\ 1195dfecf96Smrgup - Set environment to frame that called the current one.\n\ 1205dfecf96Smrg\n\ 1215dfecf96SmrgCommands may be abbreviated.\n"; 1225dfecf96Smrg 123f765521fSmrgstatic const char *debugger_info_help = 1245dfecf96Smrg"Available subcommands are:\n\ 1255dfecf96Smrg\n\ 1265dfecf96Smrgbreakpoints - List and prints status of breakpoints, and watchpoints.\n\ 1275dfecf96Smrgstack - Backtrace of stack.\n\ 1285dfecf96Smrgwatchpoints - List and prints status of watchpoints, and breakpoints.\n\ 1295dfecf96Smrg\n\ 1305dfecf96SmrgSubcommands may be abbreviated.\n"; 1315dfecf96Smrg 1325dfecf96Smrg/* Debugger variables layout (if you change it, update description): 1335dfecf96Smrg * 1345dfecf96Smrg * DBG 1355dfecf96Smrg * is a macro for lisp__data.dbglist 1365dfecf96Smrg * is a NIL terminated list 1375dfecf96Smrg * every element is a list in the format (NOT NIL terminated): 1385dfecf96Smrg * (list* NAM ARG ENV HED LEX) 1395dfecf96Smrg * where 1405dfecf96Smrg * NAM is an ATOM for the function/macro name 1415dfecf96Smrg * or NIL for lambda expressions 1425dfecf96Smrg * ARG is NAM arguments (a LIST) 1435dfecf96Smrg * ENV is the value of lisp__data.stack.base (a FIXNUM) 1445dfecf96Smrg * LEN is the value of lisp__data.env.length (a FIXNUM) 1455dfecf96Smrg * LEX is the value of lisp__data.env.lex (a FIXNUM) 1465dfecf96Smrg * new elements are added to the beggining of the DBG list 1475dfecf96Smrg * 1485dfecf96Smrg * BRK 1495dfecf96Smrg * is macro for lisp__data.brklist 1505dfecf96Smrg * is a NIL terminated list 1515dfecf96Smrg * every element is a list in the format (NIL terminated): 1525dfecf96Smrg * (list NAM IDX TYP HIT VAR VAL FRM) 1535dfecf96Smrg * where 1545dfecf96Smrg * NAM is an ATOM for the name of the object at 1555dfecf96Smrg * wich the breakpoint was added 1565dfecf96Smrg * IDX is a FIXNUM, the breakpoint number 1575dfecf96Smrg * must be stored, as breakpoints may be deleted 1585dfecf96Smrg * TYP is a FIXNUM that must be an integer of enum LispBreakType 1595dfecf96Smrg * HIT is a FIXNUM, with the number of times this breakpoint was 1605dfecf96Smrg * hitted. 1615dfecf96Smrg * VAR variable to watch a SYMBOL (not needed for breakpoints) 1625dfecf96Smrg * VAL value of watched variable (not needed for breakpoints) 1635dfecf96Smrg * FRM frame where variable started being watched 1645dfecf96Smrg * (not needed for breakpoints) 1655dfecf96Smrg * new elements are added to the end of the list 1665dfecf96Smrg */ 1675dfecf96Smrg 1685dfecf96Smrg/* 1695dfecf96Smrg * Implementation 1705dfecf96Smrg */ 1715dfecf96Smrgvoid 1725dfecf96SmrgLispDebugger(LispDebugCall call, LispObj *name, LispObj *arg) 1735dfecf96Smrg{ 1745dfecf96Smrg int force = 0; 1755dfecf96Smrg LispObj *obj, *prev; 1765dfecf96Smrg 1775dfecf96Smrg switch (call) { 1785dfecf96Smrg case LispDebugCallBegin: 1795dfecf96Smrg ++lisp__data.debug_level; 1805dfecf96Smrg GCDisable(); 1815dfecf96Smrg DBG = CONS(CONS(name, CONS(arg, CONS(FIXNUM(lisp__data.stack.base), 1825dfecf96Smrg CONS(FIXNUM(lisp__data.env.length), 1835dfecf96Smrg FIXNUM(lisp__data.env.lex))))), DBG); 1845dfecf96Smrg GCEnable(); 1855dfecf96Smrg for (obj = BRK; obj != NIL; obj = CDR(obj)) 1865dfecf96Smrg if (ATOMID(CAR(CAR(obj))) == ATOMID(name) && 1875dfecf96Smrg FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj))))) == 1885dfecf96Smrg LispDebugBreakFunction) 1895dfecf96Smrg break; 1905dfecf96Smrg if (obj != NIL) { 1915dfecf96Smrg long counter; 1925dfecf96Smrg 1935dfecf96Smrg /* if not at a fresh line */ 1945dfecf96Smrg if (LispGetColumn(NIL)) 1955dfecf96Smrg LispFputc(Stdout, '\n'); 1965dfecf96Smrg LispFputs(Stdout, "BREAK #"); 1975dfecf96Smrg LispWriteObject(NIL, CAR(CDR(CAR(obj)))); 1985dfecf96Smrg LispFputs(Stdout, "> ("); 1995dfecf96Smrg LispWriteObject(NIL, CAR(CAR(DBG))); 2005dfecf96Smrg LispFputc(Stdout, ' '); 2015dfecf96Smrg LispWriteObject(NIL, CAR(CDR(CAR(DBG)))); 2025dfecf96Smrg LispFputs(Stdout, ")\n"); 2035dfecf96Smrg force = 1; 2045dfecf96Smrg /* update hits counter */ 2055dfecf96Smrg counter = FIXNUM_VALUE(CAR(CDR(CDR(CDR(CAR(obj)))))); 2065dfecf96Smrg CAR(CDR(CDR(CDR(CAR(obj))))) FIXNUM(counter + 1); 2075dfecf96Smrg } 2085dfecf96Smrg break; 2095dfecf96Smrg case LispDebugCallEnd: 2105dfecf96Smrg DBG = CDR(DBG); 2115dfecf96Smrg if (lisp__data.debug_level < lisp__data.debug_step) 2125dfecf96Smrg lisp__data.debug_step = lisp__data.debug_level; 2135dfecf96Smrg --lisp__data.debug_level; 2145dfecf96Smrg break; 2155dfecf96Smrg case LispDebugCallFatal: 2165dfecf96Smrg LispDebuggerCommand(NIL); 2175dfecf96Smrg return; 2185dfecf96Smrg case LispDebugCallWatch: 2195dfecf96Smrg break; 2205dfecf96Smrg } 2215dfecf96Smrg 2225dfecf96Smrg /* didn't return, check watchpoints */ 2235dfecf96Smrg if (call == LispDebugCallEnd || call == LispDebugCallWatch) { 2245dfecf96Smrgwatch_again: 2255dfecf96Smrg for (prev = obj = BRK; obj != NIL; prev = obj, obj = CDR(obj)) { 2265dfecf96Smrg if (FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj))))) == 2275dfecf96Smrg LispDebugBreakVariable) { 2285dfecf96Smrg /* the variable */ 2295dfecf96Smrg LispObj *wat = CAR(CDR(CDR(CDR(CDR(CAR(obj)))))); 2305dfecf96Smrg void *sym = LispGetVarAddr(CAAR(obj)); 2315dfecf96Smrg LispObj *frm = CAR(CDR(CDR(CDR(CDR(CDR(CDR(CAR(obj)))))))); 2325dfecf96Smrg 2335dfecf96Smrg if ((sym == NULL && lisp__data.debug_level <= 0) || 2345dfecf96Smrg (sym != wat->data.opaque.data && 2355dfecf96Smrg FIXNUM_VALUE(frm) > lisp__data.debug_level)) { 2365dfecf96Smrg LispFputs(Stdout, "WATCH #"); 2375dfecf96Smrg LispFputs(Stdout, format_integer(FIXNUM_VALUE(CAR(CDR(CAR(obj)))))); 2385dfecf96Smrg LispFputs(Stdout, "> "); 2395dfecf96Smrg LispFputs(Stdout, STRPTR(CAR(CAR(obj)))); 2405dfecf96Smrg LispFputs(Stdout, " deleted. Variable does not exist anymore.\n"); 2415dfecf96Smrg /* force debugger to stop */ 2425dfecf96Smrg force = 1; 2435dfecf96Smrg if (obj == prev) { 2445dfecf96Smrg BRK = CDR(BRK); 2455dfecf96Smrg goto watch_again; 2465dfecf96Smrg } 2475dfecf96Smrg else 2485dfecf96Smrg RPLACD(prev, CDR(obj)); 2495dfecf96Smrg obj = prev; 2505dfecf96Smrg } 2515dfecf96Smrg else { 2525dfecf96Smrg /* current value */ 2535dfecf96Smrg LispObj *cur = *(LispObj**)wat->data.opaque.data; 2545dfecf96Smrg /* last value */ 2555dfecf96Smrg LispObj *val = CAR(CDR(CDR(CDR(CDR(CDR(CAR(obj))))))); 2565dfecf96Smrg if (XEQUAL(val, cur) == NIL) { 2575dfecf96Smrg long counter; 2585dfecf96Smrg 2595dfecf96Smrg LispFputs(Stdout, "WATCH #"); 2605dfecf96Smrg LispFputs(Stdout, format_integer(FIXNUM_VALUE(CAR(CDR(CAR(obj)))))); 2615dfecf96Smrg LispFputs(Stdout, "> "); 2625dfecf96Smrg LispFputs(Stdout, STRPTR(CAR(CAR(obj)))); 2635dfecf96Smrg LispFputc(Stdout, '\n'); 2645dfecf96Smrg 2655dfecf96Smrg LispFputs(Stdout, "OLD: "); 2665dfecf96Smrg LispWriteObject(NIL, val); 2675dfecf96Smrg 2685dfecf96Smrg LispFputs(Stdout, "\nNEW: "); 2695dfecf96Smrg LispWriteObject(NIL, cur); 2705dfecf96Smrg LispFputc(Stdout, '\n'); 2715dfecf96Smrg 2725dfecf96Smrg /* update current value */ 2735dfecf96Smrg CAR(CDR(CDR(CDR(CDR(CDR(CAR(obj))))))) = cur; 2745dfecf96Smrg /* update hits counter */ 2755dfecf96Smrg counter = FIXNUM_VALUE(CAR(CDR(CDR(CDR(CAR(obj)))))); 2765dfecf96Smrg CAR(CDR(CDR(CDR(CAR(obj))))) = FIXNUM(counter + 1); 2775dfecf96Smrg /* force debugger to stop */ 2785dfecf96Smrg force = 1; 2795dfecf96Smrg } 2805dfecf96Smrg } 2815dfecf96Smrg } 2825dfecf96Smrg } 2835dfecf96Smrg 2845dfecf96Smrg if (call == LispDebugCallWatch) 2855dfecf96Smrg /* special call, just don't keep gc protected variables that may be 2865dfecf96Smrg * using a lot of memory... */ 2875dfecf96Smrg return; 2885dfecf96Smrg } 2895dfecf96Smrg 2905dfecf96Smrg switch (lisp__data.debug) { 2915dfecf96Smrg case LispDebugUnspec: 2925dfecf96Smrg LispDebuggerCommand(NIL); 2935dfecf96Smrg goto debugger_done; 2945dfecf96Smrg case LispDebugRun: 2955dfecf96Smrg if (force) 2965dfecf96Smrg LispDebuggerCommand(NIL); 2975dfecf96Smrg goto debugger_done; 2985dfecf96Smrg case LispDebugFinish: 2995dfecf96Smrg if (!force && 3005dfecf96Smrg (call != LispDebugCallEnd || 3015dfecf96Smrg lisp__data.debug_level != lisp__data.debug_step)) 3025dfecf96Smrg goto debugger_done; 3035dfecf96Smrg break; 3045dfecf96Smrg case LispDebugNext: 3055dfecf96Smrg if (call == LispDebugCallBegin) { 3065dfecf96Smrg if (!force && lisp__data.debug_level != lisp__data.debug_step) 3075dfecf96Smrg goto debugger_done; 3085dfecf96Smrg } 3095dfecf96Smrg else if (call == LispDebugCallEnd) { 3105dfecf96Smrg if (!force && lisp__data.debug_level >= lisp__data.debug_step) 3115dfecf96Smrg goto debugger_done; 3125dfecf96Smrg } 3135dfecf96Smrg break; 3145dfecf96Smrg case LispDebugStep: 3155dfecf96Smrg break; 3165dfecf96Smrg } 3175dfecf96Smrg 3185dfecf96Smrg if (call == LispDebugCallBegin) { 3195dfecf96Smrg LispFputc(Stdout, '#'); 3205dfecf96Smrg LispFputs(Stdout, format_integer(lisp__data.debug_level)); 3215dfecf96Smrg LispFputs(Stdout, "> ("); 3225dfecf96Smrg LispWriteObject(NIL, CAR(CAR(DBG))); 3235dfecf96Smrg LispFputc(Stdout, ' '); 3245dfecf96Smrg LispWriteObject(NIL, CAR(CDR(CAR(DBG)))); 3255dfecf96Smrg LispFputs(Stdout, ")\n"); 3265dfecf96Smrg LispDebuggerCommand(NIL); 3275dfecf96Smrg } 3285dfecf96Smrg else if (call == LispDebugCallEnd) { 3295dfecf96Smrg LispFputc(Stdout, '#'); 3305dfecf96Smrg LispFputs(Stdout, format_integer(lisp__data.debug_level + 1)); 3315dfecf96Smrg LispFputs(Stdout, "= "); 3325dfecf96Smrg LispWriteObject(NIL, arg); 3335dfecf96Smrg LispFputc(Stdout, '\n'); 3345dfecf96Smrg LispDebuggerCommand(NIL); 3355dfecf96Smrg } 3365dfecf96Smrg else if (force) 3375dfecf96Smrg LispDebuggerCommand(arg); 3385dfecf96Smrg 3395dfecf96Smrgdebugger_done: 3405dfecf96Smrg return; 3415dfecf96Smrg} 3425dfecf96Smrg 3435dfecf96Smrgstatic void 3445dfecf96SmrgLispDebuggerCommand(LispObj *args) 3455dfecf96Smrg{ 3465dfecf96Smrg LispObj *obj, *frm, *curframe; 3475dfecf96Smrg int i = 0, frame, matches, action = -1, subaction = 0; 3485dfecf96Smrg char *cmd, *arg, *ptr, line[256]; 3495dfecf96Smrg 3505dfecf96Smrg int envbase = lisp__data.stack.base, 3515dfecf96Smrg envlen = lisp__data.env.length, 3525dfecf96Smrg envlex = lisp__data.env.lex; 3535dfecf96Smrg 3545dfecf96Smrg frame = lisp__data.debug_level; 3555dfecf96Smrg curframe = CAR(DBG); 3565dfecf96Smrg 3575dfecf96Smrg line[0] = '\0'; 3585dfecf96Smrg arg = line; 3595dfecf96Smrg for (;;) { 3605dfecf96Smrg LispFputs(Stdout, DBGPROMPT); 3615dfecf96Smrg LispFflush(Stdout); 3625dfecf96Smrg if (LispFgets(Stdin, line, sizeof(line)) == NULL) { 3635dfecf96Smrg LispFputc(Stdout, '\n'); 3645dfecf96Smrg return; 3655dfecf96Smrg } 3665dfecf96Smrg /* get command */ 3675dfecf96Smrg ptr = line; 3685dfecf96Smrg while (*ptr && isspace(*ptr)) 3695dfecf96Smrg ++ptr; 3705dfecf96Smrg cmd = ptr; 3715dfecf96Smrg while (*ptr && !isspace(*ptr)) 3725dfecf96Smrg ++ptr; 3735dfecf96Smrg if (*ptr) 3745dfecf96Smrg *ptr++ = '\0'; 3755dfecf96Smrg 3765dfecf96Smrg if (*cmd) { /* if *cmd is nul, then arg may be still set */ 3775dfecf96Smrg /* get argument(s) */ 3785dfecf96Smrg while (*ptr && isspace(*ptr)) 3795dfecf96Smrg ++ptr; 3805dfecf96Smrg arg = ptr; 3815dfecf96Smrg /* goto end of line */ 3825dfecf96Smrg if (*ptr) { 3835dfecf96Smrg while (*ptr) 3845dfecf96Smrg ++ptr; 3855dfecf96Smrg --ptr; 3865dfecf96Smrg while (*ptr && isspace(*ptr)) 3875dfecf96Smrg --ptr; 3885dfecf96Smrg if (*ptr) 3895dfecf96Smrg *++ptr = '\0'; 3905dfecf96Smrg } 3915dfecf96Smrg } 3925dfecf96Smrg 3935dfecf96Smrg if (*cmd == '\0') { 3945dfecf96Smrg if (action < 0) { 3955dfecf96Smrg if (lisp__data.debug == LispDebugFinish) 3965dfecf96Smrg action = DebuggerFinish; 3975dfecf96Smrg else if (lisp__data.debug == LispDebugNext) 3985dfecf96Smrg action = DebuggerNext; 3995dfecf96Smrg else if (lisp__data.debug == LispDebugStep) 4005dfecf96Smrg action = DebuggerStep; 4015dfecf96Smrg else if (lisp__data.debug == LispDebugRun) 4025dfecf96Smrg action = DebuggerContinue; 4035dfecf96Smrg else 4045dfecf96Smrg continue; 4055dfecf96Smrg } 4065dfecf96Smrg } 4075dfecf96Smrg else { 4085dfecf96Smrg for (i = matches = 0; i < sizeof(commands) / sizeof(commands[0]); 4095dfecf96Smrg i++) { 410f765521fSmrg const char *str = commands[i].name; 4115dfecf96Smrg 4125dfecf96Smrg ptr = cmd; 4135dfecf96Smrg while (*ptr && *ptr == *str) { 4145dfecf96Smrg ++ptr; 4155dfecf96Smrg ++str; 4165dfecf96Smrg } 4175dfecf96Smrg if (*ptr == '\0') { 4185dfecf96Smrg action = commands[i].action; 4195dfecf96Smrg if (*str == '\0') { 4205dfecf96Smrg matches = 1; 4215dfecf96Smrg break; 4225dfecf96Smrg } 4235dfecf96Smrg ++matches; 4245dfecf96Smrg } 4255dfecf96Smrg } 4265dfecf96Smrg if (matches == 0) { 4275dfecf96Smrg LispFputs(Stdout, "* Command unknown: "); 4285dfecf96Smrg LispFputs(Stdout, cmd); 4295dfecf96Smrg LispFputs(Stdout, ". Type help for help.\n"); 4305dfecf96Smrg continue; 4315dfecf96Smrg } 4325dfecf96Smrg else if (matches > 1) { 4335dfecf96Smrg LispFputs(Stdout, "* Command is ambiguous: "); 4345dfecf96Smrg LispFputs(Stdout, cmd); 4355dfecf96Smrg LispFputs(Stdout, ". Type help for help.\n"); 4365dfecf96Smrg continue; 4375dfecf96Smrg } 4385dfecf96Smrg } 4395dfecf96Smrg 4405dfecf96Smrg switch (action) { 4415dfecf96Smrg case DebuggerHelp: 4425dfecf96Smrg LispFputs(Stdout, debugger_help); 4435dfecf96Smrg break; 4445dfecf96Smrg case DebuggerInfo: 4455dfecf96Smrg if (*arg == '\0') { 4465dfecf96Smrg LispFputs(Stdout, debugger_info_help); 4475dfecf96Smrg break; 4485dfecf96Smrg } 4495dfecf96Smrg 4505dfecf96Smrg for (i = matches = 0; 4515dfecf96Smrg i < sizeof(info_commands) / sizeof(info_commands[0]); 4525dfecf96Smrg i++) { 453f765521fSmrg const char *str = info_commands[i].name; 4545dfecf96Smrg 4555dfecf96Smrg ptr = arg; 4565dfecf96Smrg while (*ptr && *ptr == *str) { 4575dfecf96Smrg ++ptr; 4585dfecf96Smrg ++str; 4595dfecf96Smrg } 4605dfecf96Smrg if (*ptr == '\0') { 4615dfecf96Smrg subaction = info_commands[i].subaction; 4625dfecf96Smrg if (*str == '\0') { 4635dfecf96Smrg matches = 1; 4645dfecf96Smrg break; 4655dfecf96Smrg } 4665dfecf96Smrg ++matches; 4675dfecf96Smrg } 4685dfecf96Smrg } 4695dfecf96Smrg if (matches == 0) { 4705dfecf96Smrg LispFputs(Stdout, "* Command unknown: "); 4715dfecf96Smrg LispFputs(Stdout, arg); 4725dfecf96Smrg LispFputs(Stdout, ". Type info for help.\n"); 4735dfecf96Smrg continue; 4745dfecf96Smrg } 4755dfecf96Smrg else if (matches > 1) { 4765dfecf96Smrg LispFputs(Stdout, "* Command is ambiguous: "); 4775dfecf96Smrg LispFputs(Stdout, arg); 4785dfecf96Smrg LispFputs(Stdout, ". Type info for help.\n"); 4795dfecf96Smrg continue; 4805dfecf96Smrg } 4815dfecf96Smrg 4825dfecf96Smrg switch (subaction) { 4835dfecf96Smrg case DebuggerInfoBreakpoints: 4845dfecf96Smrg LispFputs(Stdout, "Num\tHits\tType\t\tWhat\n"); 4855dfecf96Smrg for (obj = BRK; obj != NIL; obj = CDR(obj)) { 4865dfecf96Smrg /* breakpoint number */ 4875dfecf96Smrg LispFputc(Stdout, '#'); 4885dfecf96Smrg LispWriteObject(NIL, CAR(CDR(CAR(obj)))); 4895dfecf96Smrg 4905dfecf96Smrg /* number of hits */ 4915dfecf96Smrg LispFputc(Stdout, '\t'); 4925dfecf96Smrg LispWriteObject(NIL, CAR(CDR(CDR(CDR(CAR(obj)))))); 4935dfecf96Smrg 4945dfecf96Smrg /* breakpoint type */ 4955dfecf96Smrg LispFputc(Stdout, '\t'); 4965dfecf96Smrg switch ((int)FIXNUM_VALUE(CAR(CDR(CDR(CAR(obj)))))) { 4975dfecf96Smrg case LispDebugBreakFunction: 4985dfecf96Smrg LispFputs(Stdout, "Function"); 4995dfecf96Smrg break; 5005dfecf96Smrg case LispDebugBreakVariable: 5015dfecf96Smrg LispFputs(Stdout, "Variable"); 5025dfecf96Smrg break; 5035dfecf96Smrg } 5045dfecf96Smrg 5055dfecf96Smrg /* breakpoint object */ 5065dfecf96Smrg LispFputc(Stdout, '\t'); 5075dfecf96Smrg LispWriteObject(NIL, CAR(CAR(obj))); 5085dfecf96Smrg LispFputc(Stdout, '\n'); 5095dfecf96Smrg } 5105dfecf96Smrg break; 5115dfecf96Smrg case DebuggerInfoBacktrace: 5125dfecf96Smrg goto debugger_print_backtrace; 5135dfecf96Smrg } 5145dfecf96Smrg break; 5155dfecf96Smrg case DebuggerAbort: 5165dfecf96Smrg while (lisp__data.mem.level) { 5175dfecf96Smrg --lisp__data.mem.level; 5185dfecf96Smrg if (lisp__data.mem.mem[lisp__data.mem.level]) 5195dfecf96Smrg free(lisp__data.mem.mem[lisp__data.mem.level]); 5205dfecf96Smrg } 5215dfecf96Smrg lisp__data.mem.index = 0; 5225dfecf96Smrg LispTopLevel(); 5235dfecf96Smrg if (!lisp__data.running) { 5245dfecf96Smrg LispMessage("*** Fatal: nowhere to longjmp."); 5255dfecf96Smrg abort(); 5265dfecf96Smrg } 5275dfecf96Smrg /* don't need to restore environment */ 5285dfecf96Smrg siglongjmp(lisp__data.jmp, 1); 5295dfecf96Smrg /*NOTREACHED*/ 5305dfecf96Smrg break; 5315dfecf96Smrg case DebuggerBreak: 5325dfecf96Smrg for (ptr = arg; *ptr; ptr++) { 5335dfecf96Smrg if (isspace(*ptr)) 5345dfecf96Smrg break; 5355dfecf96Smrg else 5365dfecf96Smrg *ptr = toupper(*ptr); 5375dfecf96Smrg } 5385dfecf96Smrg 5395dfecf96Smrg if (!*arg || *ptr || strchr(arg, '(') || strchr(arg, '(') || 5405dfecf96Smrg strchr(arg, ';')) { 5415dfecf96Smrg LispFputs(Stdout, "* Bad function name '"); 5425dfecf96Smrg LispFputs(Stdout, arg); 5435dfecf96Smrg LispFputs(Stdout, "' specified.\n"); 5445dfecf96Smrg } 5455dfecf96Smrg else { 5465dfecf96Smrg for (obj = frm = BRK; obj != NIL; frm = obj, obj = CDR(obj)) 5475dfecf96Smrg ; 5485dfecf96Smrg i = lisp__data.debug_break; 5495dfecf96Smrg ++lisp__data.debug_break; 5505dfecf96Smrg GCDisable(); 5515dfecf96Smrg obj = CONS(ATOM(arg), 5525dfecf96Smrg CONS(FIXNUM(i), 5535dfecf96Smrg CONS(FIXNUM(LispDebugBreakFunction), 5545dfecf96Smrg CONS(FIXNUM(0), NIL)))); 5555dfecf96Smrg if (BRK == NIL) 5565dfecf96Smrg BRK = CONS(obj, NIL); 5575dfecf96Smrg else 5585dfecf96Smrg RPLACD(frm, CONS(obj, NIL)); 5595dfecf96Smrg GCEnable(); 5605dfecf96Smrg } 5615dfecf96Smrg break; 5625dfecf96Smrg case DebuggerWatch: { 5635dfecf96Smrg void *sym; 5645dfecf96Smrg int vframe; 5655dfecf96Smrg LispObj *val, *atom; 5665dfecf96Smrg 5675dfecf96Smrg /* make variable name uppercase, an ATOM */ 5685dfecf96Smrg ptr = arg; 5695dfecf96Smrg while (*ptr) { 5705dfecf96Smrg *ptr = toupper(*ptr); 5715dfecf96Smrg ++ptr; 5725dfecf96Smrg } 5735dfecf96Smrg atom = ATOM(arg); 5745dfecf96Smrg val = LispGetVar(atom); 5755dfecf96Smrg if (val == NULL) { 5765dfecf96Smrg LispFputs(Stdout, "* No variable named '"); 5775dfecf96Smrg LispFputs(Stdout, arg); 5785dfecf96Smrg LispFputs(Stdout, "' in the selected frame.\n"); 5795dfecf96Smrg break; 5805dfecf96Smrg } 5815dfecf96Smrg 5825dfecf96Smrg /* variable is available at the current frame */ 5835dfecf96Smrg sym = LispGetVarAddr(atom); 5845dfecf96Smrg 5855dfecf96Smrg /* find the lowest frame where the variable is visible */ 5865dfecf96Smrg vframe = 0; 5875dfecf96Smrg if (frame > 0) { 5885dfecf96Smrg for (; vframe < frame; vframe++) { 5895dfecf96Smrg for (frm = DBG, i = lisp__data.debug_level; i > vframe; 5905dfecf96Smrg frm = CDR(frm), i--) 5915dfecf96Smrg ; 5925dfecf96Smrg obj = CAR(frm); 5935dfecf96Smrg lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(obj)))); 5945dfecf96Smrg lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(obj))))); 5955dfecf96Smrg lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(obj))))); 5965dfecf96Smrg 5975dfecf96Smrg if (LispGetVarAddr(atom) == sym) 5985dfecf96Smrg /* got variable initial frame */ 5995dfecf96Smrg break; 6005dfecf96Smrg } 6015dfecf96Smrg vframe = i; 6025dfecf96Smrg if (vframe != frame) { 6035dfecf96Smrg /* restore environment */ 6045dfecf96Smrg for (frm = DBG, i = lisp__data.debug_level; i > frame; 6055dfecf96Smrg frm = CDR(frm), i--) 6065dfecf96Smrg ; 6075dfecf96Smrg obj = CAR(frm); 6085dfecf96Smrg lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(obj)))); 6095dfecf96Smrg lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(obj))))); 6105dfecf96Smrg lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(obj))))); 6115dfecf96Smrg } 6125dfecf96Smrg } 6135dfecf96Smrg 6145dfecf96Smrg i = lisp__data.debug_break; 6155dfecf96Smrg ++lisp__data.debug_break; 6165dfecf96Smrg for (obj = frm = BRK; obj != NIL; frm = obj, obj = CDR(obj)) 6175dfecf96Smrg ; 6185dfecf96Smrg 6195dfecf96Smrg GCDisable(); 6205dfecf96Smrg obj = CONS(atom, /* NAM */ 6215dfecf96Smrg CONS(FIXNUM(i), /* IDX */ 6225dfecf96Smrg CONS(FIXNUM(LispDebugBreakVariable), /* TYP */ 6235dfecf96Smrg CONS(FIXNUM(0), /* HIT */ 6245dfecf96Smrg CONS(OPAQUE(sym, 0), /* VAR */ 6255dfecf96Smrg CONS(val, /* VAL */ 6265dfecf96Smrg CONS(FIXNUM(vframe),/* FRM */ 6275dfecf96Smrg NIL))))))); 6285dfecf96Smrg 6295dfecf96Smrg /* add watchpoint */ 6305dfecf96Smrg if (BRK == NIL) 6315dfecf96Smrg BRK = CONS(obj, NIL); 6325dfecf96Smrg else 6335dfecf96Smrg RPLACD(frm, CONS(obj, NIL)); 6345dfecf96Smrg GCEnable(); 6355dfecf96Smrg } break; 6365dfecf96Smrg case DebuggerDelete: 6375dfecf96Smrg if (*arg == 0) { 6385dfecf96Smrg int confirm = 0; 6395dfecf96Smrg 6405dfecf96Smrg for (;;) { 6415dfecf96Smrg int ch; 6425dfecf96Smrg 6435dfecf96Smrg LispFputs(Stdout, "* Delete all breakpoints? (y or n) "); 6445dfecf96Smrg LispFflush(Stdout); 6455dfecf96Smrg if ((ch = LispFgetc(Stdin)) == '\n') 6465dfecf96Smrg continue; 6475dfecf96Smrg while ((i = LispFgetc(Stdin)) != '\n' && i != EOF) 6485dfecf96Smrg ; 6495dfecf96Smrg if (tolower(ch) == 'n') 6505dfecf96Smrg break; 6515dfecf96Smrg else if (tolower(ch) == 'y') { 6525dfecf96Smrg confirm = 1; 6535dfecf96Smrg break; 6545dfecf96Smrg } 6555dfecf96Smrg } 6565dfecf96Smrg if (confirm) 6575dfecf96Smrg BRK = NIL; 6585dfecf96Smrg } 6595dfecf96Smrg else { 6605dfecf96Smrg for (ptr = arg; *ptr;) { 6615dfecf96Smrg while (*ptr && isdigit(*ptr)) 6625dfecf96Smrg ++ptr; 6635dfecf96Smrg if (*ptr && !isspace(*ptr)) { 6645dfecf96Smrg *ptr = '\0'; 6655dfecf96Smrg LispFputs(Stdout, "* Bad breakpoint number '"); 6665dfecf96Smrg LispFputs(Stdout, arg); 6675dfecf96Smrg LispFputs(Stdout, "' specified.\n"); 6685dfecf96Smrg break; 6695dfecf96Smrg } 6705dfecf96Smrg i = atoi(arg); 6715dfecf96Smrg for (obj = frm = BRK; frm != NIL; 6725dfecf96Smrg obj = frm, frm = CDR(frm)) 6735dfecf96Smrg if (FIXNUM_VALUE(CAR(CDR(CAR(frm)))) == i) 6745dfecf96Smrg break; 6755dfecf96Smrg if (frm == NIL) { 6765dfecf96Smrg LispFputs(Stdout, "* No breakpoint number "); 6775dfecf96Smrg LispFputs(Stdout, arg); 6785dfecf96Smrg LispFputs(Stdout, " available.\n"); 6795dfecf96Smrg break; 6805dfecf96Smrg } 6815dfecf96Smrg if (obj == frm) 6825dfecf96Smrg BRK = CDR(BRK); 6835dfecf96Smrg else 6845dfecf96Smrg RPLACD(obj, CDR(frm)); 6855dfecf96Smrg while (*ptr && isspace(*ptr)) 6865dfecf96Smrg ++ptr; 6875dfecf96Smrg arg = ptr; 6885dfecf96Smrg } 6895dfecf96Smrg } 6905dfecf96Smrg break; 6915dfecf96Smrg case DebuggerFrame: 6925dfecf96Smrg i = -1; 6935dfecf96Smrg ptr = arg; 6945dfecf96Smrg if (*ptr) { 6955dfecf96Smrg i = 0; 6965dfecf96Smrg while (*ptr && isdigit(*ptr)) { 6975dfecf96Smrg i *= 10; 6985dfecf96Smrg i += *ptr - '0'; 6995dfecf96Smrg ++ptr; 7005dfecf96Smrg } 7015dfecf96Smrg if (*ptr) { 7025dfecf96Smrg LispFputs(Stdout, "* Frame identifier must " 7035dfecf96Smrg "be a positive number.\n"); 7045dfecf96Smrg break; 7055dfecf96Smrg } 7065dfecf96Smrg } 7075dfecf96Smrg else 7085dfecf96Smrg goto debugger_print_frame; 7095dfecf96Smrg if (i >= 0 && i <= lisp__data.debug_level) 7105dfecf96Smrg goto debugger_new_frame; 7115dfecf96Smrg LispFputs(Stdout, "* No such frame "); 7125dfecf96Smrg LispFputs(Stdout, format_integer(i)); 7135dfecf96Smrg LispFputs(Stdout, ".\n"); 7145dfecf96Smrg break; 7155dfecf96Smrg case DebuggerDown: 7165dfecf96Smrg if (frame + 1 > lisp__data.debug_level) { 7175dfecf96Smrg LispFputs(Stdout, "* Cannot go down.\n"); 7185dfecf96Smrg break; 7195dfecf96Smrg } 7205dfecf96Smrg i = frame + 1; 7215dfecf96Smrg goto debugger_new_frame; 7225dfecf96Smrg break; 7235dfecf96Smrg case DebuggerUp: 7245dfecf96Smrg if (frame == 0) { 7255dfecf96Smrg LispFputs(Stdout, "* Cannot go up.\n"); 7265dfecf96Smrg break; 7275dfecf96Smrg } 7285dfecf96Smrg i = frame - 1; 7295dfecf96Smrg goto debugger_new_frame; 7305dfecf96Smrg break; 7315dfecf96Smrg case DebuggerPrint: 7325dfecf96Smrg ptr = arg; 7335dfecf96Smrg while (*ptr) { 7345dfecf96Smrg *ptr = toupper(*ptr); 7355dfecf96Smrg ++ptr; 7365dfecf96Smrg } 7375dfecf96Smrg obj = LispGetVar(ATOM(arg)); 7385dfecf96Smrg if (obj != NULL) { 7395dfecf96Smrg LispWriteObject(NIL, obj); 7405dfecf96Smrg LispFputc(Stdout, '\n'); 7415dfecf96Smrg } 7425dfecf96Smrg else { 7435dfecf96Smrg LispFputs(Stdout, "* No variable named '"); 7445dfecf96Smrg LispFputs(Stdout, arg); 7455dfecf96Smrg LispFputs(Stdout, "' in the selected frame.\n"); 7465dfecf96Smrg } 7475dfecf96Smrg break; 7485dfecf96Smrg case DebuggerBacktrace: 7495dfecf96Smrgdebugger_print_backtrace: 7505dfecf96Smrg if (DBG == NIL) { 7515dfecf96Smrg LispFputs(Stdout, "* No stack.\n"); 7525dfecf96Smrg break; 7535dfecf96Smrg } 7545dfecf96Smrg DBG = LispReverse(DBG); 7555dfecf96Smrg for (obj = DBG, i = 0; obj != NIL; obj = CDR(obj), i++) { 7565dfecf96Smrg frm = CAR(obj); 7575dfecf96Smrg LispFputc(Stdout, '#'); 7585dfecf96Smrg LispFputs(Stdout, format_integer(i)); 7595dfecf96Smrg LispFputs(Stdout, "> ("); 7605dfecf96Smrg LispWriteObject(NIL, CAR(frm)); 7615dfecf96Smrg LispFputc(Stdout, ' '); 7625dfecf96Smrg LispWriteObject(NIL, CAR(CDR(frm))); 7635dfecf96Smrg LispFputs(Stdout, ")\n"); 7645dfecf96Smrg } 7655dfecf96Smrg DBG = LispReverse(DBG); 7665dfecf96Smrg break; 7675dfecf96Smrg case DebuggerContinue: 7685dfecf96Smrg lisp__data.debug = LispDebugRun; 7695dfecf96Smrg goto debugger_command_done; 7705dfecf96Smrg case DebuggerFinish: 7715dfecf96Smrg if (lisp__data.debug != LispDebugFinish) { 7725dfecf96Smrg lisp__data.debug_step = lisp__data.debug_level - 2; 7735dfecf96Smrg lisp__data.debug = LispDebugFinish; 7745dfecf96Smrg } 7755dfecf96Smrg else 7765dfecf96Smrg lisp__data.debug_step = lisp__data.debug_level - 1; 7775dfecf96Smrg goto debugger_command_done; 7785dfecf96Smrg case DebuggerNext: 7795dfecf96Smrg if (lisp__data.debug != LispDebugNext) { 7805dfecf96Smrg lisp__data.debug = LispDebugNext; 7815dfecf96Smrg lisp__data.debug_step = lisp__data.debug_level + 1; 7825dfecf96Smrg } 7835dfecf96Smrg goto debugger_command_done; 7845dfecf96Smrg case DebuggerStep: 7855dfecf96Smrg lisp__data.debug = LispDebugStep; 7865dfecf96Smrg goto debugger_command_done; 7875dfecf96Smrg } 7885dfecf96Smrg continue; 7895dfecf96Smrg 7905dfecf96Smrgdebugger_new_frame: 7915dfecf96Smrg /* goto here with i as the new frame value, after error checking */ 7925dfecf96Smrg if (i != frame) { 7935dfecf96Smrg frame = i; 7945dfecf96Smrg for (frm = DBG, i = lisp__data.debug_level; 7955dfecf96Smrg i > frame; frm = CDR(frm), i--) 7965dfecf96Smrg ; 7975dfecf96Smrg curframe = CAR(frm); 7985dfecf96Smrg lisp__data.stack.base = FIXNUM_VALUE(CAR(CDR(CDR(curframe)))); 7995dfecf96Smrg lisp__data.env.length = FIXNUM_VALUE(CAR(CDR(CDR(CDR(curframe))))); 8005dfecf96Smrg lisp__data.env.lex = FIXNUM_VALUE(CDR(CDR(CDR(CDR(curframe))))); 8015dfecf96Smrg } 8025dfecf96Smrgdebugger_print_frame: 8035dfecf96Smrg LispFputc(Stdout, '#'); 8045dfecf96Smrg LispFputs(Stdout, format_integer(frame)); 8055dfecf96Smrg LispFputs(Stdout, "> ("); 8065dfecf96Smrg LispWriteObject(NIL, CAR(curframe)); 8075dfecf96Smrg LispFputc(Stdout, ' '); 8085dfecf96Smrg LispWriteObject(NIL, CAR(CDR(curframe))); 8095dfecf96Smrg LispFputs(Stdout, ")\n"); 8105dfecf96Smrg } 8115dfecf96Smrg 8125dfecf96Smrgdebugger_command_done: 8135dfecf96Smrg lisp__data.stack.base = envbase; 8145dfecf96Smrg lisp__data.env.length = envlen; 8155dfecf96Smrg lisp__data.env.lex = envlex; 8165dfecf96Smrg} 8175dfecf96Smrg 8185dfecf96Smrgstatic char * 8195dfecf96Smrgformat_integer(int integer) 8205dfecf96Smrg{ 8215dfecf96Smrg static char buffer[16]; 8225dfecf96Smrg 8235dfecf96Smrg sprintf(buffer, "%d", integer); 8245dfecf96Smrg 8255dfecf96Smrg return (buffer); 8265dfecf96Smrg} 8275dfecf96Smrg 8285dfecf96Smrg#endif /* DEBUGGER */ 829