From bf2261244ad64be1ba7d2cf09017e17d586b26a5 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Mon, 6 Apr 1992 18:40:40 +0000 Subject: *** empty log message *** --- gdb/cadillac.c | 916 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 780 insertions(+), 136 deletions(-) diff --git a/gdb/cadillac.c b/gdb/cadillac.c index 936a4fc..22e7968 100755 --- a/gdb/cadillac.c +++ b/gdb/cadillac.c @@ -17,7 +17,10 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include "defs.h" +#include "symtab.h" +#include "inferior.h" +#include "command.h" #include #include #include @@ -26,6 +29,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* Connection block for debugger<=>kernel communications. */ static Connection *conn = 0; @@ -35,7 +47,24 @@ static int kerfd; /* The kernel's ID for this instance of the program. */ static int program_id; + +static int instance_id; + +/* The fd for the pty associated with the inferior. */ +static int inferior_pty = -1; +static int inferior_tty = -1; + +static int has_run = 0; + +extern int cadillac; + +char **pprompt; /* Pointer to pointer to prompt */ +static void +prompt() +{ + fputs_filtered(*pprompt, stdout); +} /* This routine redirects the output of fputs_filtered to the kernel so that the user can see what's going on in his debugger window. */ @@ -44,34 +73,658 @@ void cadillac_fputs(ptr) char *ptr; { + if (conn) + CVWriteTranscriptInfo (conn, instance_id, ptr); + else + fputs (ptr, stdout); +} + +/* Copy all data from the pty to the kernel. */ + +static void +pty_to_kernel() +{ CTtyRequest *req; + char buf[1024]; + int cc; - if (conn) + while (1) { - req = CWriteTtyRequest (conn, TextIORType); - CWriteVstring0 (conn, ptr); - CWriteLength (conn); -/* CWriteRequestBuffer (conn); /* XXX - debugging only */ + cc = read(inferior_pty, buf, sizeof(buf)); + + if (cc == 0 + || (cc < 0 + && errno == EWOULDBLOCK)) + break; + + if (cc < 0) + { + close(inferior_pty); + inferior_pty = -1; + perror("pty read error"); + break; + } + + req = CWriteTtyRequest(conn, TextIORType); + CWriteVstringLen(conn, buf, cc); + CWriteLength(conn); + } + CWriteRequestBuffer(conn); +} + +/* Copy data from the kernel to the pty. */ + +static void +kernel_to_pty(data, len) + char *data; + int len; +{ + int cc; + + cc = write(inferior_pty, data, len); + + if (cc != len) + { + if (cc < 0) + { + close(inferior_pty); + inferior_pty = -1; + perror("pty write error"); + return; + } + printf("Couldn't write all the data to the pty, wanted %d, got %d\n", + len, cc); } - else - fputs (ptr, stdout); +} + +/* Tell the kernel where we are in the program, and what the stack looks like. + */ + +static void +send_status() +{ + static int linecount = 48; + struct symtab_and_line sal; + struct symbol *symbol; + char *funcname, *filename; + static int foo = 0; + static int sent_prog_inst = 0; + + if (!has_run) + return; + + if (inferior_pid == 0) /* target has died */ + { + CVWriteProgramTerminatedInfo(conn, + instance_id, + "" + ); + return; + } + + sal = find_pc_line(stop_pc, 0); + symbol = find_pc_function(stop_pc); + + funcname = symbol ? symbol->name : ""; + filename = sal.symtab ? sal.symtab->filename : ""; + + if (!sent_prog_inst) + { + sent_prog_inst = 1; + CVWriteProgramInstanceInfo(conn, + program_id, + instance_id, + "", /* hostname */ + "", /* arglist */ + "" + ); + } + + CVWriteStackSizeInfo(conn, + instance_id, + 1, /* XXX - frame depth */ + CInnerFrameIs0, + foo++ ? 1 : 0, /* XXX - frame diff */ + "" + ); + + CVWriteStackFrameInfo(conn, + instance_id, + sal.line, + CFileLinePos, + 0, /* XXX - frame # */ + funcname, + filename, + "" /* XXX ? transcript */ + ); + + CVWriteProgramStoppedInfo(conn, + instance_id, + 0, /* XXX - breakpoint # or signal # */ + CDebuggerCommand, + funcname, + "" /* XXX ? transcript */ + ); +} + +/* Tell the kernel that the target is now running. */ + +static void +go_busy() +{ + CVWriteProgramBusyInfo(conn, + instance_id, + ""); /* XXX ? transcript */ + CWriteRequestBuffer(conn); /* Must take place synchronusly! */ } /* This wrapper routine is needed because execute_command modifies the command string that it's given. It also echos the commands. */ static void -execute_command_1 (cmd, from_tty) - char *cmd; - int from_tty; +execute_command_1(va_alist) + va_dcl { - char buf[100]; + char buf[100]; /* XXX - make buf dynamic! */ + char *cmd; + va_list args; + + va_start(args); - printf_filtered("%s\n", cmd); - strcpy(buf, cmd); - execute_command(buf, from_tty); + cmd = va_arg(args, char *); + + vsprintf(buf, cmd, args); + + printf_filtered("%s\n", buf); + execute_command(buf, 1); + + va_end(args); } +#ifdef KERNEL_RECORD +FILE *kerout; + +static int +kernel_record(fd, ptr, num) + int fd, num; + char *ptr; + +{ + fwrite(ptr, num, 1, kerout); + fflush(kerout); + return write(fd, ptr, num); +} +#endif + +void +cadillac_condition_breakpoint(b) + struct breakpoint *b; +{ + CVWriteBreakConditionInfo(conn, + instance_id, + b->number, + b->cond_string ? b->cond_string : "", + "" /* transcript */ + ); +} + +void +cadillac_commands_breakpoint(b) + struct breakpoint *b; +{ + struct command_line *l; + + CVWriteBreakCommandBegInfo(conn, + instance_id, + b->number, + ""); /* transcript */ + + for (l = b->commands; l; l = l->next) + CVWriteBreakCommandEntryInfo(conn, + instance_id, + l->line, + ""); /* transcript */ + + CVWriteBreakCommandEndInfo(conn, + instance_id, + ""); /* transcript */ +} + +static void +breakpoint_notify(b, action) + struct breakpoint *b; + int action; +{ + struct symtab *s; + struct symbol *s1; + char *funcname = "", *filename = "", *included_in_filename = ""; + + if (b->type != bp_breakpoint) + return; + + s = b->symtab; + + if (s) + { + filename = s->filename; + s1 = find_pc_function(b->address); + if (s1) + funcname = SYMBOL_NAME(s1); + } + + CVWriteBreakpointInfo (conn, + instance_id, + b->number, + b->line_number, + CFileLinePos, + CBreakOnInstrAccess, + action, + b->ignore_count, + funcname, + filename, + "", /* included_in_filename */ + "" /* transcript */ + ); + + if (b->commands) + cadillac_commands_breakpoint(b); +} + +void +cadillac_create_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, CEnableBreakpoint); +} + +void +cadillac_delete_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, CDeleteBreakpoint); +} + +void +cadillac_enable_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, CEnableBreakpoint); +} + +void +cadillac_disable_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, CDisableBreakpoint); +} + +void +cadillac_ignore_breakpoint(b) + struct breakpoint *b; +{ + breakpoint_notify(b, CBreakAttrUnchanged); +} + +static int command_line_length = 0; +static char *command_line_text = 0; + +int +cadillac_reading() +{ + if (command_line_text) + return 1; + else + return 0; +} + +char * +cadillac_command_line_input() +{ + char *p; + + if (command_line_length <= 0) + return (char *)NULL; + + p = command_line_text; + + while (command_line_length-- > 0) + { + if (*command_line_text == '\n') + { + *command_line_text = '\000'; + command_line_text++; + break; + } + command_line_text++; + } + + return p; +} + +/* Open up a pty and its associated tty. Return the fd of the tty. */ + +char * +cadillac_getpty() +{ + int n, ptyfd, ttyfd; + static char dev[30]; + struct stat statbuf; + struct termios termios; + +#define HIGHPTY (('z' - 'p') * 16 - 1) + + if (inferior_pty >= 0) /* Only do this once */ + return dev; + + for (n = 0; n <= HIGHPTY; n++) + { + sprintf(dev, "/dev/pty%c%x", n/16 + 'p', n%16); + if (stat(dev, &statbuf)) + break; + ptyfd = open(dev, O_RDWR); + if (ptyfd < 0) + continue; + sprintf(dev, "/dev/tty%c%x", n/16 + 'p', n%16); + ttyfd = open(dev, O_RDWR); + if (ttyfd < 0) {close(ptyfd); continue;} + + /* Setup pty for non-blocking I/O. Also make it give us a SIGIO when + there's data available. */ + + n = fcntl(ptyfd, F_GETFL, 0); + fcntl(ptyfd, F_SETFL, n|FNDELAY|FASYNC); + fcntl(ptyfd, F_SETOWN, getpid()); + + tcgetattr(ttyfd, &termios); + termios.c_oflag &= ~OPOST; /* No post-processing */ + tcsetattr(ttyfd, TCSANOW, &termios); + + inferior_pty = ptyfd; + inferior_tty = ttyfd; + return dev; + } + + error ("getpty: can't get a pty\n"); +} + +/* Examine a protocol packet from the driver. */ + +static int +kernel_dispatch(interrupt) + int interrupt; /* Non-zero means we are at interrupt level + and can only do a few commands. */ +{ + register CHeader *head; + + head = (CHeader *)CPeekNextRequest (conn); + if (head == NULL) + { + fprintf (stderr, "EOF on kernel read!\n"); + exit (1); + } + + if (interrupt) + switch (head->reqType) + { + case KillProgramRType: + case TextIORType: + case StopRType: + break; + default: + return; + } + + if (head->reqType < LastTtyRequestRType) + { + CTtyRequest* req = CReadTtyRequest (conn); + switch (req->head.reqType) + { + case AcceptConnectionRType: + /* Tell the rest of the world that cadillac is now set up */ + CSkipRequest (conn); + break; + + case RefuseConnectionRType: + fprintf (stderr, "Debugger connection refused\n"); + exit (1); + + case KillProgramRType: + exit (0); + + case TextIORType: + { + char *p; + ReqLen len; + + p = CGetVstring(conn, &len); + kernel_to_pty(p, len); + } + break; + default: + fprintf(stderr, "Unknown request type = %d\n", + req->head.reqType); + break; + } + } + else + { + CVDebuggerRequest *req = CVReadDebuggerRequest (conn); + if (!req) + { + fprintf (stderr, "CVReadDebuggerRequest returned NULL, type = %d\n", + head->reqType); + exit(1); + } + + switch (req->head.request->reqType) + { + case OpenProgramInstanceRType: + { + char *arglist, buf[100]; /* XXX - Make buf dynamic! */ + int arglen; + /* XXX - should notice when program_id changes */ + arglist = req->openProgramInstance.progArglist.text; + arglen = req->openProgramInstance.progArglist.byteLen; + + execute_command_1("break main"); + execute_command_1("enable delete $bpnum"); + if (arglist) + { + execute_command_1("set args %.*s", arglen, arglist); + } + execute_command_1("run"); + } + break; + case QuitDebuggerRType: + exit (0); + case RunRType: + if (req->run.request->useArglist == CNewArglist) + { + execute_command_1("set args %.*s", + req->run.progArglist.byteLen, + req->run.progArglist.text); + } + execute_command_1("run"); + break; + case ContinueRType: + execute_command_1("continue"); + break; + case StepRType: + execute_command_1("step %d", req->step.request->stepCount); + break; + case NextRType: + execute_command_1("next %d", req->next.request->nextCount); + break; + case ChangeStackFrameRType: + switch (req->changeStackFrame.request->frameMovement) + { + case CToCurrentStackFrame: + execute_command_1("frame %d", + req->changeStackFrame.request->frameNo); + break; + case CToInnerStackFrame: + execute_command_1("down %d", + req->changeStackFrame.request->frameNo); + break; + case CToOuterStackFrame: + execute_command_1("up %d", + req->changeStackFrame.request->frameNo); + break; + case CToAbsoluteStackFrame: + printf_filtered("ChangeStackFrame ToAbsolute\n"); + break; + } + break; + case BackTraceRType: + /* XXX - deal with limit??? */ + execute_command_1("backtrace"); + break; + case FinishRType: + execute_command_1("finish"); + break; + case TerminateProgramRType: + execute_command_1("kill"); + break; + case NewBreakpointRType: + { + char *tail; + int skipped; + + tail = rindex(req->newBreakpoint.fileName.text, '/'); + if (!tail) + tail = req->newBreakpoint.fileName.text; + else + tail++; + skipped = tail - req->newBreakpoint.fileName.text; + execute_command_1("break %.*s:%d", + req->newBreakpoint.fileName.byteLen - skipped, + tail, + req->newBreakpoint.request->fileLinePos); + } + break; + case StopRType: + { + extern int pgrp_inferior; + killpg(pgrp_inferior, SIGINT); + } + break; + case UserInputRType: + { + char *text; + long len; + + /* XXX - should really break command up into seperate lines + and spoon-feed it to execute_command */ + + text = req->userInput.userInput.text; + len = req->userInput.userInput.byteLen; + + if (text[len-1] == '\n') text[len-1] = '\000'; + execute_command (text); + break; + } + case ChangeBreakpointRType: + switch (req->changeBreakpoint.request->breakpointAttr) + { + case CEnableBreakpoint: + execute_command_1("enable %d", + req->changeBreakpoint.request->breakpointId); + break; + case CDisableBreakpoint: + execute_command_1("disable %d", + req->changeBreakpoint.request->breakpointId); + break; + case CDeleteBreakpoint: + execute_command_1("delete %d", + req->changeBreakpoint.request->breakpointId); + break; + case CBreakAttrUnchanged: + execute_command_1("ignore %d %d", + req->changeBreakpoint.request->breakpointId, + req->changeBreakpoint.request->ignoreCount); + break; + default: + printf_filtered("Got to ChangeBreakpoint\n"); + printf_filtered(" breakpointId = %d\n", + req->changeBreakpoint.request->breakpointId); + printf_filtered(" breakpointType = %d\n", + req->changeBreakpoint.request->breakpointType); + printf_filtered(" breakpointAttr = %d\n", + req->changeBreakpoint.request->breakpointAttr); + printf_filtered(" ignoreCount = %d\n", + req->changeBreakpoint.request->ignoreCount); + break; + } + break; + case BreakConditionRType: + execute_command_1("condition %d %.*s", + req->breakCondition.request->breakpointId, + req->breakCondition.condition.byteLen, + req->breakCondition.condition.text); + break; + case BreakCommandsRType: + /* Put pointers to where cadillac_command_line_input() can find + them. */ + command_line_length = req->breakCommands.commands.byteLen; + command_line_text = req->breakCommands.commands.text; + execute_command_1("commands %d", + req->breakCommands.request->breakpointId); + command_line_text = (char *)NULL; + command_line_length = 0; + break; + default: + fprintf(stderr, "Unknown request type = %d\n", + req->head.request->reqType); + break; + } + free (req); /* Should probably call CVFreeDebuggerRequest() here, but + can't do so if interrupt level has mucked with req-> + request. CVFreeDebuggerRequest() only ends up calling + free() anyway! */ + } +} + +#define KERNEL_EVENT 1 +#define PTY_EVENT 2 + +/* Return a bitmask indicating if the kernel or the pty did something + interesting. Set poll to non-zero if you don't want to wait. */ + +static int +wait_for_events(poll) + int poll; +{ + fd_set readfds; + int numfds; + int eventmask = 0; + static struct timeval tv = {0}; + + /* Output all pending requests. */ + CWriteRequestBuffer(conn); + + /* Wait till there's some activity from the kernel or the pty. */ + do + { + FD_ZERO(&readfds); + FD_SET(kerfd, &readfds); + if (inferior_pty > 0) + FD_SET(inferior_pty, &readfds); + if (poll) + numfds = select(sizeof(readfds)*8, &readfds, 0, 0, &tv); + else + numfds = select(sizeof(readfds)*8, &readfds, 0, 0, 0); + } + while (numfds <= 0 && !poll); + + if (FD_ISSET(inferior_pty, &readfds)) + eventmask |= PTY_EVENT; + + if (FD_ISSET(kerfd, &readfds)) + eventmask |= KERNEL_EVENT; + + return eventmask; +} + /* Establish contact with the kernel. */ void @@ -83,6 +736,7 @@ cadillac_initialize(cadillac_id, execarg) char *ctmp; extern long strtol(char *str, char **ptr, int base); char pathname[MAXPATHLEN]; + int n; if (!execarg) execarg = ""; @@ -96,6 +750,12 @@ cadillac_initialize(cadillac_id, execarg) exit(1); } + /* Setup for I/O interrupts when appropriate. */ + + n = fcntl(kerfd, F_GETFL, 0); + fcntl(kerfd, F_SETFL, n|FASYNC); + fcntl(kerfd, F_SETOWN, getpid()); + /* Setup connection buffering. */ CSetSocketBufferSize (kerfd, 12000); @@ -108,6 +768,12 @@ cadillac_initialize(cadillac_id, execarg) exit(1); } +#ifdef KERNEL_RECORD + kerout = fopen("kernel.output", "+w"); + + CReadWriteHooks(conn, conn->previewMethod, conn->readMethod, kernel_record); +#endif + /* Tell the kernel that we are the "debugger". */ req = CWriteTtyRequest (conn, QueryConnectionRType); @@ -140,147 +806,125 @@ cadillac_initialize(cadillac_id, execarg) CWriteVstring0 (conn, "6"); CWriteVstring0 (conn, execarg); CWriteLength (conn); + + /* Tell the kernel our PID and all that */ + + program_id = 1; + CVWriteDebugProgramInfo(conn, + getpid(), + program_id, + execarg, + ""); + + /* Tell the rest of the world that Cadillac is now set up. */ + cadillac = 1; } -/* All requests from the Cadillac kernel eventually end up here. */ +/* This is called from execute_command, and provides a wrapper around + various command routines in a place where both protocol messages and + user input both flow through. +*/ void -cadillac_main_loop(pprompt) - char **pprompt; +cadillac_call_command(cmdblk, arg, from_tty) + struct cmd_list_element *cmdblk; + char *arg; + int from_tty; { - CTtyRequest *req; - extern int cadillac; + if (cmdblk->class == class_run) + { + go_busy(); + has_run = 1; + (*cmdblk->function.cfunc)(arg, from_tty); + send_status(); + } + else + (*cmdblk->function.cfunc)(arg, from_tty); - /* The actual event loop! */ + prompt(); +} +void +cadillac_new_process() +{ + instance_id = inferior_pid; +} + +static void +iosig() +{ while (1) { - register CHeader *head; - fd_set readfds; - int numfds; + int eventmask; - fputs_filtered(*pprompt, stdout); /* Output the prompt */ + eventmask = wait_for_events(1); - /* Output all pending requests. */ - CWriteRequestBuffer (conn); + if (eventmask == 0) + return; - /* Wait till there's some activity from the kernel. */ - while (1) - { - FD_ZERO (&readfds); - FD_SET (kerfd, &readfds); - numfds = select (sizeof(readfds)*8, &readfds, 0, 0, 0); - if (numfds > 0) break; - } + if (eventmask & PTY_EVENT) + pty_to_kernel(); - head = (CHeader *)CPeekNextRequest (conn); - if (head == NULL) - { - fprintf (stderr, "EOF on kernel read!\n"); - exit (1); - } + if (eventmask & KERNEL_EVENT) + kernel_dispatch(1); + } +} - if (head->reqType < LastTtyRequestRType) - { - CTtyRequest* req = CReadTtyRequest (conn); - switch (req->head.reqType) - { - case AcceptConnectionRType: - CSkipRequest (conn); - /* Tell the rest of the world that cadillac is now set up */ - cadillac = 1; - break; +int +cadillac_wait(status) + int *status; +{ + int pid; - case RefuseConnectionRType: - fprintf (stderr, "Debugger connection refused\n"); - exit (1); + signal(SIGIO, iosig); - case KillProgramRType: - exit (0); + pid = wait(status); - default: - fprintf_filtered(stderr, "Unknown request type = %d\n", - req->head.reqType); - CSkipRequest (conn); - break; - } - } - else - { - CVDebuggerRequest *req = CVReadDebuggerRequest (conn); - if (!req) - { - fprintf (stderr, "CVReadDebuggerRequest returned NULL, type = %d\n", - head->reqType); - return; - } + signal(SIGIO, SIG_DFL); + return pid; +} - switch (req->head.request->reqType) - { - case OpenProgramInstanceRType: - { - char *arglist, buf[100]; /* XXX - Make buf dynamic! */ - int arglen; - /* XXX - should notice when program_id changes */ - program_id = req->openProgramInstance.request->programId; - arglist = req->openProgramInstance.progArglist.text; - arglen = req->openProgramInstance.progArglist.byteLen; - - execute_command_1("break main", 1); - if (arglist) - { - sprintf(buf, "set args %.*s", arglen, arglist); - fputs_filtered(*pprompt, stdout); /* Output the prompt */ - execute_command_1(buf, 1); - } - fputs_filtered(*pprompt, stdout); /* Output the prompt */ - execute_command_1("run", 1); - } - break; - case QuitDebuggerRType: - exit (0); - case RunRType: - execute_command_1("run", 1); - break; - case ContinueRType: - execute_command_1("continue", 1); - break; - case StepRType: - execute_command_1("step", 1); - break; - case NextRType: - execute_command_1("next", 1); - break; - case ChangeStackFrameRType: - printf_filtered("Got to ChangeStackFrame\n"); - break; - case BackTraceRType: - execute_command_1("backtrace", 1); - break; - case FinishRType: - execute_command_1("finish", 1); - break; - case TerminateProgramRType: - execute_command_1("quit", 1); - break; - case UserInputRType: - { - char *text; - long len; +static void +null_routine(arg) + int arg; +{ +} - text = req->userInput.userInput.text; - len = req->userInput.userInput.byteLen; +/* All requests from the Cadillac kernel eventually end up here. */ - if (text[len-1] == '\n') text[len-1] = '\000'; - execute_command (text, 1); - break; - } - default: - fprintf_filtered(stderr, "Unknown request type = %d\n", - req->head.request->reqType); - break; - } - CVFreeDebuggerRequest (req); +void +cadillac_main_loop(pp) + char **pp; +{ + CTtyRequest *req; + struct cleanup *old_chain; + + pprompt = pp; + +/* We will come thru here any time there is an error, so send status if + necessary. */ + + send_status(); + + prompt(); + + /* The actual event loop! */ + + while (1) + { + int eventmask; + + eventmask = wait_for_events(0); + + if (eventmask & PTY_EVENT) + pty_to_kernel(); + + if (eventmask & KERNEL_EVENT) + { + old_chain = make_cleanup(null_routine, 0); + kernel_dispatch(0); + bpstat_do_actions(&stop_bpstat); + do_cleanups(old_chain); } } } -- cgit v1.1