|
|
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;
}