/***************************************************************************** * * xdbx - X Window System interface to the dbx debugger * * Copyright 1989 The University of Texas at Austin * Copyright 1990 Microelectronics and Computer Technology Corporation * * 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 The University of Texas * and Microelectronics and Computer Technology Corporation (MCC) not be * used in advertising or publicity pertaining to distribution of * the software without specific, written prior permission. The * University of Texas and MCC makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * THE UNIVERSITY OF TEXAS AND MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TEXAS OR MCC BE LIABLE FOR * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Po Cheung * Created: March 10, 1989 * ***************************************************************************** * * xxgdb - X Window System interface to the gdb debugger * * Copyright 1990 Thomson Consumer Electronics, Inc. * * 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 Thomson Consumer * Electronics (TCE) not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. TCE makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * TCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT * SHALL TCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. * * Adaptation to GDB: Pierre Willard * XXGDB Created: December, 1990 * *****************************************************************************/ /* gdb_handler.c * * WARNING : gdb_handler.c is included by handler.c for GDB. * * Contain action handlers for the parser to invoke upon a dbx command. * * updown_handler(): Update file, line label, updown arrow position. * debug_handler(): Check directory use list, display main source file. * pwd_handler(): Update current working directory. * search_handler(): Adjust source file to display matched line. * display_info_handler(): Update display window. * break_handler(): Place stop sign on line or function or address specified. * info_dir_handler(): Update search directory list. * directory_handler(): Update search directory list. * list_handler(): Adjust source file to display result. * info_line_handler(): Update current file. * delete_handler(): Remove stop sign. * display_handler(): Update display window. * info_break_handler(): Update stop signs. * cd_handler(): Record current working directory. * frame_curr_handler(): Update current function name. * exec_handler(): Update file, line label, arrow position. * done_handler(): Progrm execution completed, clear breakpoints * source_handler(): Exec commands of source file specified. * query_gdb(): Send command to gdb. */ #ifdef SYSV # include #endif /* * Display an outlined arrow to locate the calling routine in a stack * frame. */ void updown_handler() { char *func, *file; int line; line = Token.line; func = XtNewString(Token.func); if (line <= 0) line = 1; LoadCurrentFile(); if (displayedFile) file = displayedFile->pathname; if (line <= 0 || func == NULL || file == NULL) { XtFree(func); return; } if (displayedFile && strcmp(file, displayedFile->pathname)) { LoadFile(file); } updown.line = line; strcpy(updown.func, func); if (displayedFile) strcpy(updown.file, displayedFile->pathname); AdjustText(line); XtFree(func); } /* ARGSUSED */ void debug_handler() { /* debug_handler is executed at start-up and with 'symbol-file' command and with 'file' command (gdb 4.0) */ info_source_handler(NULL); /* say no current compilation directory */ query_gdb_directories(); if (new_gdb4()) /* (PW)28AUG91: test for gdb 4.0 */ { /* (SH) for gdb 4.0 */ query_gdb("set height 0\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); query_gdb("set width 0\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); query_gdb("set p pretty on\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); query_gdb("set confirm off\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); } else { query_gdb("set screensize 0\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); query_gdb("set prettyprint on\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); } displayedFile = NULL; /* force reloading of source file */ /* here we use FILTER_ON so that any error message will be displayed ! */ /* tell gdb to use main file and get line number of main(). (,main will end at main) */ query_gdb("list ,main\n", PARSE_ON | ECHO_OFF | FILTER_ON); if (displayedFile && LoadCurrentFile() == 0) /* Only if there is a current displayedFile (pavel 4-Dec-1991) */ { arrow.line = 0; /* clear arrow sign */ updown.line = 0; /* clear updown sign */ bomb.line = 0; /* clear bomb sign */ UpdateArrow(displayedFile); UpdateUpdown(displayedFile); UpdateBomb(displayedFile); ClearStops(); UpdateStops(displayedFile); } UpdateMessageWindow("Ready for execution",NULL); /* clear display window */ query_gdb("display\n", PARSE_ON | ECHO_OFF | FILTER_OFF); } /* ARGSUSED */ void pwd_handler(s) char *s; { strcpy(cwd, (char *)strtok(s, "\n")); } /* ARGSUSED */ void search_handler() { AdjustText(Token.line); } /* ARGSUSED */ /* Show output on the display window. * If output is null but the display window is managed, replace contents of * the display window with the null string. */ void display_info_handler() { Arg args[MAXARGS]; Cardinal n; #ifdef UNDISPWIN /* this code removes the display window when there is nothing to display (GWC) */ if (!Token.display || strcmp(Token.display, "") == NULL) { XtUnmanageChild(separator); XtUnmanageChild(displayWindow); return; } #endif /* UNDISPWIN */ if (!Token.display || strcmp(Token.display, "") == NULL) { if (!XtIsManaged(displayWindow)) return; else { XtFree(Token.display); Token.display = XtNewString(""); } } if (!XtIsManaged(displayWindow)) { XtManageChild(separator); XtManageChild(displayWindow); } n = 0; XtSetArg(args[n], XtNstring, (XtArgVal) Token.display); n++; XtSetValues(displayWindow, args, n); XtFree(Token.display); Token.display = 0; /*(PW)14JAN91 */ } /* Place a stop sign next to the line specified on the source file window * if it is to be viewable. */ void break_handler() { char * file; int line; int stop; if (Token.stop == 0 || Token.line == 0 || Token.file == 0) return; line = Token.line; stop = Token.stop; if (Token.stop >= 256) /* see MAXSTOPS in signs.c */ { fprintf(stderr,"Too many breakpoints\n"); return; } /* load & display file if none is displayed */ file = GetPathname(Token.file); if (file == NULL) return; /* (PW)11JAN91 */ if (displayedFile == NULL) { LoadFile(file); AdjustText(line); } stops[stop].file = file; stops[stop].line = line; stops[stop].tag = 0; nstops = stop; /* display breakpoint sign if file is displayed */ if (displayedFile) { if (!strcmp(file, displayedFile->pathname)) DisplayStop(displayedFile, line); } } /* info directories */ void info_dir_handler() { if (Token.file) MakeDirList(Token.file); } /* ARGSUSED */ void directory_handler() { /* Note : for GDB, the 'directory' command with no parameter will reset search directories to current directory only. GDB requires confirmation */ query_gdb_directories(); } void list_handler() { int line; line = Token.line; if (line) { /* update compilation directory (if gdb 4.0) before loading source file */ if (new_gdb4()) query_gdb("info source\n", PARSE_ON | ECHO_OFF | FILTER_OFF); /* We will display the last line listed. Since we used 'list ,main' we will effectively display main in that case. */ LoadCurrentFile(); AdjustText(line); } else { AppendDialogText("Error list command\n"); bell(0); } } /* ARGSUSED */ void info_line_handler() /* Command was 'info line' */ { if (Token.file) strcpy(CurrentFile, Token.file); else strcpy(CurrentFile, ""); } /* * Delete handler remove the stop specified and undisplayed the stopsign * if it's visible. * It calls the dbx status command to find out what stops are left, and * then update the array of stops accordingly. */ /* ARGSUSED */ void delete_handler() { /* update breakpoints */ query_gdb("info break\n", PARSE_ON | ECHO_OFF | FILTER_OFF); } void display_handler() /* display or undisplay */ { /* update display */ query_gdb("display\n", PARSE_ON | ECHO_OFF | FILTER_ON); } /* (gdb) info break Breakpoints: Num Enb Address Where #1 y 0x000022f4 in main (pw.c line 34) #2 y 0x000022a0 in foo (pw.c line 5) (gdb) info break No breakpoints. */ void info_break_handler(output_string) char *output_string; { int i; int line; char c; if (!output_string) return; while(*output_string) { if (*(output_string++) == '#') { if (sscanf(output_string, "%d %c", &i,&c) == 2) if (i > 0 && i <= nstops && stops[i].line > 0 && c == 'y') stops[i].tag = 1; } } for (i=1; i<=nstops; i++) if (stops[i].line > 0) { if (stops[i].tag) stops[i].tag = 0; else { line = stops[i].line; stops[i].line = 0; stops[i].file = NULL; if (LineToStop_no(line) == 0) RemoveStop(line); } } } /* ARGSUSED */ void cd_handler(s) char *s; { strcpy(cwd,s); } /* this handler justs update the function name. Because the function name is not always displayed after next,step ... */ static char* funcname = 0; void frame_curr_handler() { if (Token.func == NULL) return; if (funcname) { XtFree(funcname); funcname = 0; } funcname = XtNewString(Token.func); } /* Handle dbx output of run, cont, next, step, return commands. * Result of output parsing is returned in a set of tokens. * * If message is not 0, this is an important message and should * be displayed instead of Token.mesg. * This message will hold the Bus error and segmentation violation errors. * signal is the signal number received (if any). */ void exec_handler(message,signal) char *message; int signal; { int line, status; char *func; /* Print "stopped in ..." line in message window * Adjust text displayed */ if (Token.line == 0) return; if (message) UpdateMessageWindow(message,NULL); else UpdateMessageWindow(Token.mesg,NULL); line = Token.line; func = (Token.func) ? XtNewString(Token.func) : 0; if (Token.file) status = LoadFile(Token.file); display_info_handler(); /* uses Token.display ! */ /* because of tbreak, we have to call info break here */ query_gdb("info break\n", PARSE_ON | ECHO_OFF | FILTER_OFF); /* update breakpoints */ if (func == NULL) { /* because silly gdb 4.0 displays nothing with frame command when confirm is on (possibly a gdb bug) , I just reset confirm to on just for this command !. */ if (new_gdb4()) query_gdb("set confirm on\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); /* this will just update funcname (see frame_curr_handler()) */ query_gdb("frame\n", PARSE_ON | ECHO_OFF | FILTER_OFF); if (new_gdb4()) /* reset confirm to off */ query_gdb("set confirm off\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); func = funcname; if (func == NULL) return; funcname = 0; /* tell frame_curr_handler WE are going to XtFree it */ } arrow.line = line; /* update arrow sign position */ strcpy(arrow.func, func); updown.line = 0; /* remove updown, if any */ if (displayedFile) { strcpy(arrow.file, displayedFile->pathname); } /* Display bomb sign if segmentation fault occurs in source code */ if (status != -1 && message && signal == SIGSEGV) { arrow.line = 0; bomb.line = line; if (func) strcpy(bomb.func, func); if (displayedFile) strcpy(bomb.file, displayedFile->pathname); } else bomb.line = 0; AdjustText(line); XtFree(func); } /* Remove all the arrow and updown signs, print message, then * change the file variable to the file name displayed. */ /* ARGSUSED */ void done_handler(message,signal) char *message; int signal; { arrow.line = 0; updown.line = 0; UpdateArrow(displayedFile); UpdateUpdown(displayedFile); UpdateMessageWindow("Ready for execution",NULL); } /*--------------------------------------------------------------------------+ | | | Function to read the .gdbinit file or any source file. | | | | input : file name. | | | | output : none. | | | +--------------------------------------------------------------------------*/ void read_source_file(file) char *file; { char s[LINESIZ]; FILE *fp; if (fp = fopen(file, "r")) { while (fgets(s, LINESIZ, fp)) { /* Check for comment line, DO NOT SEND '\n', Take care of source command, Take care of define or document commands. */ if ((*s != '#') && strcmp(s,"\n")) { if (!(gdb_source_command(s,TRUE) || gdb_define_command(s,fp))) query_gdb(s, PARSE_ON | ECHO_ON | FILTER_ON); } } fclose(fp); } } /* WARNING : source_handler() is NOT called by the parser. It is called by gdb_source_command() in gdb_parser.c. This is because 'source' command is NEVER sent to gdb, instead xxgdb sends the commands in the specified file one by one. */ void source_handler() { char *file; if (!Token.file || strcmp(Token.file, "") == NULL) { XtFree(Token.file); Token.file = XtNewString(".gdbinit"); /* default is .gdbinit */ } file = GetPathname(Token.file); if (file == NULL) return; /* (PW)11JAN91 */ read_source_file(file); } /* core-file * gdb does not display current line, file, func ..., so we send * 'frame 0' command to have them. */ void core_file_handler() { char *message; int line; int signal; message = XtNewString(Token.mesg); signal = Token.stop; /* signal number received */ /* because silly gdb 4.0 displays nothing with frame command when confirm is on (possibly a gdb bug) , I just reset confirm to on just for this command !. */ if (new_gdb4()) query_gdb("set confirm on\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); /* this will update updown.line, updown.func and updown.file. (see updown_handler) */ query_gdb("frame 0\n", PARSE_ON | ECHO_OFF | FILTER_OFF); if (new_gdb4()) /* reset confirm to off */ query_gdb("set confirm off\n", PARSE_OFF | ECHO_OFF | FILTER_OFF); line = updown.line; updown.line = 0; /* Display bomb sign if segmentation fault occurred in source code */ if (line != 0 && signal == SIGSEGV) { arrow.line = 0; bomb.line = line; strcpy(bomb.func, updown.func); strcpy(bomb.file, updown.file); } else { bomb.line = 0; arrow.line = line; strcpy(arrow.func, updown.func); strcpy(arrow.file, updown.file); } UpdateMessageWindow(message,NULL); XtFree(message); AdjustText(line); } /*--------------------------------------------------------------------------+ | | | Function to get the current source path directories. | | | | WARNING : this function is called at startup of xxgdb | | to test for gdb 4.0 or earlier versions. | | The 1st time that query_gdb_directories() is called, | | new_gdb is true, and 'show directories' command is | | issued to gdb. Then parse() in gdb_parser.c will test for | | 'show Unknown command' answer from gdb, and in that case | | will set new_gdb to false. See show_is_undefined() below. | | | +--------------------------------------------------------------------------*/ void query_gdb_directories() { if (new_gdb4()) /* (PW)28AUG91: test for gdb 4.0 */ query_gdb("show directories\n", PARSE_ON | ECHO_OFF | FILTER_OFF); else query_gdb("info directories\n", PARSE_ON | ECHO_OFF | FILTER_OFF); } /*--------------------------------------------------------------------------+ | | | Function to know if we are running the NEW gdb | | | | return TRUE if we are running gdb 4.0 (or 3.9x or higher) | | | | WARNING : it is important that the default is gdb 4.0. | | (see comments on query_gdb_directories() above). | | | +--------------------------------------------------------------------------*/ static int new_gdb = True; /* default : we are running gdb 4.0 */ int new_gdb4() { return new_gdb; } /*--------------------------------------------------------------------------+ | | | Function to say that 'show' command is undefined and thus | | that we are running an old version of gdb. | | | +--------------------------------------------------------------------------*/ void show_is_undefined() { new_gdb = False; } /*--------------------------------------------------------------------------+ | | | Update compilation directory | | | | This function is used for gdb 4.0 which uses the compilation | | directory in the source path. | | | | input : current compilation directory | | (returned from 'info source' gdb command). | | | | output : none. | | | +--------------------------------------------------------------------------*/ char cdir[MAXPATHLEN]; /* The compilation directory */ void info_source_handler(compile_dir) char * compile_dir; { if (compile_dir == NULL) { cdir[0] = 0; return; } if (strlen (compile_dir) < MAXPATHLEN) /* check length */ strcpy(cdir,compile_dir); if (LASTCH(cdir) == '/') /* remove last '/' */ LASTCH(cdir) = '\0'; }