|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 20149 (0x4eb5) Types: TextFile Names: »gdb.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦e10a7c8ba⟧ »./UNRELEASED/xgdb.tar.Z« └─⟦ae30648b5⟧ └─⟦this⟧ »./gdb.c«
\f #ifndef lint static char rcsid[] = "$Header: gdb.c,v 1.1 89/07/05 15:36:02 hubbard Exp $"; #endif /* * * Copyright 1988, 1989 * PCS Computer Systeme, GmbH * Munich, West Germany * * All rights reserved. * * This is unsupported software and is subject to change without notice. * PCS makes no representations about the suitability of this software * for any purpose. It is supplied "as is" without express or implied * warranty. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of PCS Computer Systeme not be used in * advertising or publicity pertaining to distribution of the software * without specific, written prior permission. * */ /* * Author: Jordan K. Hubbard * For: PCS Computer Systems, GmbH. * When: February 10th, 1989. * * $Log: gdb.c,v $ * Revision 1.1 89/07/05 15:36:02 hubbard * Initial revision * * */ #include "xgdb.h" #include <errno.h> /* * Debugger-dependent stuff for the GNU debugger (gdb). */ String debuggerPrintOutput(), debuggerParseErrors(), debuggerParseInfo(); /* * Foreward declarations for the "input region" commands. These are not * much different from the command functions, the only reason for * seperating them being that they make more sense when presented next * to the input region itself. */ void quitp(), clear(), restart(); /* * These arrays mate command names to their function callbacks. */ SimpleField DebuggerCommands[] = { { "Run", debuggerRun }, { "Continue", debuggerContinue }, { "Kill", debuggerKill }, { "Step", debuggerStep }, { "StepT", debuggerStepThrough }, { "StepU", debuggerStepUntil }, { "StepF", debuggerStepFinish }, { "StepI", debuggerStepI }, { "StepIT", debuggerStepIThrough }, { "Search>", debuggerSearchForward }, { "Search<", debuggerSearchBackward }, { "Up", debuggerUp }, { "Down", debuggerDown }, { "Break", debuggerAddBkpt }, { "Delete", debuggerDeleteBkpt }, { "Clear", debuggerClearBkpt }, { "Enable", debuggerEnableBkpt }, { "Disable", debuggerDisableBkpt }, { "exec", debuggerExecFile }, { "symbol", debuggerSymbolFile }, { "core", debuggerCoreFile }, { "cd", debuggerChangeDirectory }, { "dir", debuggerSetDirectory }, { "tty", debuggerSetTTY }, { NULL, NULL } }; SimpleField InputRegionCommands[] = { { "Quit", quitp }, { "Restart", restart }, { NULL, NULL } }; SimpleField Options[] = { { ASSEMBLY_N, assemblyCreateView }, { AUTOEXEC_N, autoExecCreateView }, { BREAKPOINTS_N, breakCreateView }, { SOURCE_N, sourceCreateView }, { STACK_N, stackCreateView }, { STATUS_N, statusCreateView }, { NULL, NULL } }; /* * First the utility routines. */ /* * Largest chunk of data we reasonably expect to receive. This can * be too small, as the buffer will just grow in HandleOutput(), * but for efficiency reasons it should be as large as the largest * chunk of output expected from gdb. */ #define MAX_TRANS 4096 void processDebuggerOutput(client_data, src, id) caddr_t client_data; int *src; XtInputId *id; { char buffer[MAX_TRANS]; Cardinal i; Entry("processDebuggerOutput"); if ((i = read(DebuggerProcess->in_channel, buffer, MAX_TRANS)) < 1) { Leave_void; } else { viewChangeCursor(DebuggerProcess->view, app_resources.cursors.busy, TRUE); /* Use the generic handler */ handleOutput(DebuggerProcess, buffer, i); } Leave_void; } /* * What to do when the debugger snuffs it. */ void handleDebuggerTermination(pd, wait_stat) Process *pd; int wait_stat; { int status; Entry("handleDebuggerTermination"); disableProcessHandling(); status = wait_stat & 0xffff; if ((status & 0xff00) == 0x7f00) puke_and_die("Couldn't execute debugger '%s'", app_resources.debugger); else { displayTerminationStatus(pd, wait_stat); flushPendingOutput(pd); /* Get rid of all the output */ if (pd->in_id) XtRemoveInput(pd->in_id); if (pd->out_id) XtRemoveInput(pd->out_id); close(pd->in_channel); close(pd->out_channel); } enableProcessHandling(); Leave_void; } /* * gdb-specific preliminary setup work. */ void setInitialDebuggerState(pd) Process *pd; { Entry("setInitialDebuggerState"); /* * What's the debugger's prompt look like? */ DebuggerPrompt = "(gdb) "; /* * What are all the different prompts gdb might print? */ DebuggerPromptRegexp = "(gdb) \\|(y or n) "; /* * Declare a generic handler to catch any output not handled by * by anyone else. */ Generic = installParser(debuggerPrintOutput); /* * Install the error message parser. */ installParser(debuggerParseErrors); /* * Install the main parser. */ installParser(debuggerParseInfo); Leave_void; } /* * Create the argument list. */ void setDebuggerArgs(name) String name; { static String program_args[9]; Cardinal i, n; Entry("setDebuggerArgs"); /* * Construct gdb's args based on what we were passsed. */ i = 0; program_args[i++] = name; program_args[i++] = "-fullname"; for (n = 1; n < Global_ac; n++) program_args[i++] = Global_av[n]; program_args[i] = NULL; DebuggerArgs = program_args; Leave_void; } /* * The command functions. */ void debuggerRun(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static SimpleParser run[] = { { "StE1", T_ARG, { SO(S_exec_file) } }, { NULL, 0, { NULL } }, }; Entry("debuggerRun"); tmp = getInputAsString("run ", '\n'); queueDebuggerTrans(tmp, run, NULL); XtFree(tmp); Leave_void; } void debuggerContinue(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static SimpleParser except[] = { { "NORN", T_PROC,{ (caddr_t)popupErrorMessage } }, { "CONT", T_NOP, { NULL } }, { NULL, 0, { NULL } }, }; Entry("debuggerContinue"); tmp = getInputAsString("cont ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); Leave_void; } void debuggerKill(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { Entry("debuggerKill"); queueDebuggerTrans("kill\n", NULL, NULL); Leave_void; } /* * Step one source line. */ void debuggerStep(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerStep"); tmp = getInputAsString("step ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } /* * Step one source line, moving "through" function calls (that is, over * them). */ void debuggerStepThrough(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerStepThrough"); tmp = getInputAsString("next ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } /* * Step one instruction. */ void debuggerStepI(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerStepI"); tmp = getInputAsString("stepi ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } /* * Step one instruction, passing over subroutine calls. */ void debuggerStepIThrough(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerStepIThrough"); tmp = getInputAsString("nexti ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } /* * Step until the end of the current function is reached. */ void debuggerStepFinish(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static SimpleParser fin[] = { { "FINI", T_NOP, { NULL } }, { "FINV", T_NOP, { NULL } }, { NULL, 0, { NULL } }, }; Entry("debuggerStepFinish"); tmp = getInputAsString("finish ", '\n'); queueDebuggerTrans(tmp, fin, NULL); XtFree(tmp); Leave_void; } /* * Step until a source line > than the current is reached, * or until a given line is reached (arg) OR at the end of * the current function. */ void debuggerStepUntil(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerStepUntil"); tmp = getInputAsString("until ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } void debuggerUp(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static SimpleParser except[] = { { "NOUP", T_PROC0, { (caddr_t)feep } }, { NULL, 0, { NULL } }, }; Entry("debuggerUp"); tmp = getInputAsString("up ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); Leave_void; } void debuggerDown(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static SimpleParser except[] = { { "NODN", T_PROC0, { (caddr_t)feep } }, { NULL, 0, { NULL } }, }; Entry("debuggerDown"); tmp = getInputAsString("down ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); Leave_void; } void debuggerSetFrame(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { Entry("debuggerSetFrame"); if (w == (Widget)NULL) { char buf[30]; sprintf(buf, "frame %d\n", (int)data); queueDebuggerTrans(buf, NULL, NULL); } Leave_void; } void debuggerAddBkpt(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; static void handleMultipleBkpts(); static SimpleParser except[] = { { "BPMU", T_PROC, { (caddr_t)handleMultipleBkpts } }, { "BPBD", T_PROC0, { (caddr_t)feep } }, { NULL, 0, { NULL } }, }; Entry("debuggerAddBkpt"); /* * If NULL, We were invoked from some other part of the program, * not a button. */ if (w == (Widget)NULL) { char buf[30]; switch ((int)client_data) { case T_LINE: /* Line number */ sprintf(buf, "break %d\n", (int)data); queueDebuggerTrans(buf, except, NULL); break; case T_ADDRESS: /* Hex address */ sprintf(buf, "break *0x%x\n", (long)data); queueDebuggerTrans(buf, except, NULL); break; default: puke("%p: Don't know break type for #%d", (int)client_data); break; } } else { tmp = getInputAsString("break ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); } Leave_void; } void debuggerClearBkpt(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerClearBkpt"); if (w == (Widget)NULL) { /* called non-interactivly */ char buf[30]; sprintf(buf, "clear %d\n", (int)data); queueDebuggerTrans(buf, NULL, NULL); } else { tmp = getInputAsString("clear ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); } Leave_void; } void debuggerDeleteBkpt(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerDeleteBkpt"); if (w == (Widget)NULL) { /* called non-interactivly */ char buf[30]; sprintf(buf, "delete %d\n", (int)data); queueDebuggerTrans(buf, NULL, NULL); } else { tmp = getInputAsString("delete ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); } Leave_void; } void debuggerDisableBkpt(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerDisableBkpt"); if (w == (Widget)NULL) { /* called non-interactivly */ char buf[40]; sprintf(buf, "disable breakpoint %d\n", (int)data); queueDebuggerTrans(buf, NULL, NULL); } else { tmp = getInputAsString("disable breakpoint ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); } Leave_void; } void debuggerEnableBkpt(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerEnableBkpt"); if (w == (Widget)NULL) { /* called non-interactivly */ char buf[40]; sprintf(buf, "enable breakpoint %d\n", (int)data); queueDebuggerTrans(buf, NULL, NULL); } else { tmp = getInputAsString("enable breakpoint ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); } Leave_void; } void debuggerSearchForward(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { static void searchSucceeded(); String tmp; static SimpleParser except[] = { { "SE1", T_PROC0,{ (caddr_t)feep } }, { "SE2", T_PROC, { (caddr_t)popupErrorMessage } }, { "SE3", T_PROC, { (caddr_t)popupErrorMessage } }, { "SE4", T_PROC, { (caddr_t)searchSucceeded } }, { NULL, 0, { NULL } }, }; Entry("debuggerSearchForward"); tmp = getInputAsString("forward-search ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); Leave_void; } void debuggerSearchBackward(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { static void searchSucceeded(); String tmp; static SimpleParser except[] = { { "SE1", T_PROC0, { (caddr_t)feep } }, { "SE2", T_PROC, { (caddr_t)popupErrorMessage } }, { "SE3", T_PROC, { (caddr_t)popupErrorMessage } }, { "SE4", T_PROC, { (caddr_t)searchSucceeded } }, { NULL, 0, { NULL } }, }; Entry("debuggerSearchBackward"); tmp = getInputAsString("reverse-search ", '\n'); queueDebuggerTrans(tmp, except, NULL); XtFree(tmp); Leave_void; } void debuggerExecFile(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerExecFile"); tmp = getInputAsString("exec-file ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } void debuggerSymbolFile(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerSymbolFile"); tmp = getInputAsString("symbol-file ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } void debuggerCoreFile(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerCoreFile"); tmp = getInputAsString("core-file ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } void debuggerChangeDirectory(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerChangeDirectory"); tmp = getInputAsString("cd ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } void debuggerSetDirectory(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerSetDirectory"); tmp = getInputAsString("dir ", '\n'); queueDebuggerTrans(tmp, NULL, NULL); XtFree(tmp); Leave_void; } /* * Set the debugged process's output to the selected tty/file. If no * file is selected, or it cannot be opened, do nothing. */ void debuggerSetTTY(w, client_data, data) Widget w; caddr_t client_data; caddr_t data; { String tmp; Entry("debuggerSetTTY"); tmp = getInputAsString(NULL, '\0'); if (tmp && strlen(tmp)) { char buf[MAXPATHLEN + 19]; if (!access(buf, 0x06)) { sprintf(buf, "tty %s\n", tmp); queueDebuggerTrans(buf, NULL, NULL); } else { sprintf(buf, "Can't open file '%s'", tmp); popupErrorMessage(NULL, buf, strlen(buf)); } } else { /* Redirect to, or create slave xterm */ } Leave_void; } /* * Debugger query functions. A query function either sets state so that * one of the update functions catches the change sometime later, or it * calls one of the view public procedures directly from a parser. */ /* Get status information, usually for status view */ void debuggerQueryStatus() { static SimpleParser dirs[] = { { "StPa", T_ARG, { SO(S_file_path) } }, { NULL, 0, { NULL } }, }; static SimpleParser pwd[] = { { "StD1", T_ARG, { SO(S_dir) } }, { "StD2", T_ARG, { SO(S_dir) } }, { NULL, 0, { NULL } }, }; static SimpleParser files[] = { { "STQ1", T_NOP, { NULL } }, { "STQ2", T_NOP, { NULL } }, { "STQ3", T_NOP, { NULL } }, { "STQ4", T_NOP, { NULL } }, { "StS1", T_ARG, { SO(S_symbol_file) } }, { "StS2", T_ARG, { SO(S_symbol_file) } }, { "StE1", T_ARG, { SO(S_exec_file) } }, { "StE2", T_ARG, { SO(S_exec_file) } }, { "StC1", T_ARG, { SO(S_core_file) } }, { "StT1", T_ARG, { SO(S_text_segment) } }, { "Std1", T_ARG, { SO(S_data_segment) } }, { "Std2", T_ARG, { SO(S_data_segment) } }, { "Sts1", T_ARG, { SO(S_stack_segment) } }, { NULL, 0, { NULL } }, }; Entry("debuggerQueryStatus"); queueDebuggerTrans("info files\n", files, NULL); queueDebuggerTrans("info directories\n", dirs, NULL); queueDebuggerTrans("pwd\n", pwd, NULL); Leave_void; } /* Find out which breakpoints are set */ void debuggerQueryBreakpoints() { static SimpleParser bkpts[] = { { "BPP1", T_PROCS, { (caddr_t)breakAddBreakpoint } }, { "BPP2", T_PROCS, { (caddr_t)breakAddBreakpoint } }, { "BPP3", T_NOP, { NULL } }, { "BPP4", T_NOP, { NULL } }, { NULL, 0, { NULL } }, }; Entry("debuggerQueryBreakpoints"); queueDebuggerTrans("info breakpoints\n", bkpts, NULL); Leave_void; } /* Find out which source file to start with */ void debuggerQueryInitialSource() { static SimpleParser src[] = { { "SLQ1", T_ARG, { SO(S_file) } }, { "SLQ2", T_NOP, { NULL } }, { NULL, 0, { NULL } }, }; Entry("debuggerQueryInitialSource"); /* KLUUUUUUUUDGE */ queueDebuggerTrans("info line 0\n", src, NULL); Leave_void; } /* * Look at the current stack. */ void debuggerQueryStack() { Entry("debuggerQueryStack"); queueDebuggerTrans("where\n", NULL, NULL); Leave_void; } /* * Get the disassembled code for the current function. */ void debuggerQueryFunction() { static SimpleParser func[] = { { "ASDX", T_NOP, { NULL } }, { NULL, 0, { NULL } }, }; Entry("debuggerQueryFunction"); if (assemblyMapped()) { toggleOutputThreshold(); queueDebuggerTrans("asdump\n", func, assemblyDisplayFunction); } Leave_void; } /* * various parser service routines. */ /* * Deal with more than one breakpoint at a location. */ static void handleMultipleBkpts(T_PROC_ARGS) T_PROC_DECL; { Entry("handleMultipleBkpts"); printf("Multiple breakpoint..\n"); Leave_void; } /* * Parse out line number information from a successful search. */ static void searchSucceeded(T_PROC_ARGS) T_PROC_DECL; { int line = 0; char *np; void searchRequestFile(); Entry("searchSucceeded"); /* * Yes, we go from ascii->integer->ascii here, but it's necessary * for error checking. Since searches aren't done all *that* often, * the expense is negligible. */ line = atoi(s); if (!line) puke("%p: bad line number returned by search!"); else { /* No file selected in the source window? */ if (!strcmp(dbg_state.S_file, INITIAL)) { static SimpleParser except[] = { { "SS", T_ARGS, { SO(S_line), SO(S_file) } }, { NULL, 0, { NULL } }, }; queueDebuggerTrans("info line\n", except, NULL); } else { np = (String)itoa(line); STASH(dbg_state.S_line, np); } } Leave_void; }