/* List lines of source files for GDB, the GNU debugger.
- Copyright 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994
+ Copyright 1986, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 1998
Free Software Foundation, Inc.
This file is part of GDB.
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. */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "symtab.h"
#include "command.h"
#include "gdbcmd.h"
#include "frame.h"
+#include "value.h"
#include <sys/types.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/stat.h>
+#include "gdb_string.h"
+#include "gdb_stat.h"
#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "gdbcore.h"
-#include "regex.h"
+#include "gnu-regex.h"
#include "symfile.h"
#include "objfiles.h"
#include "annotate.h"
+#include "gdbtypes.h"
+
+#ifdef CRLF_SOURCE_FILES
-#ifndef DIRNAME_SEPARATOR
-#define DIRNAME_SEPARATOR ':'
+/* Define CRLF_SOURCE_FILES in an xm-*.h file if source files on the
+ host use \r\n rather than just \n. Defining CRLF_SOURCE_FILES is
+ much faster than defining LSEEK_NOT_LINEAR. */
+
+#ifndef O_BINARY
+#define O_BINARY 0
#endif
+#define OPEN_MODE (O_RDONLY | O_BINARY)
+#define FDOPEN_MODE FOPEN_RB
+
+#else /* ! defined (CRLF_SOURCE_FILES) */
+
+#define OPEN_MODE O_RDONLY
+#define FDOPEN_MODE FOPEN_RT
+
+#endif /* ! defined (CRLF_SOURCE_FILES) */
+
/* Prototypes for local functions. */
static int open_source_file PARAMS ((struct symtab *));
static void find_source_lines PARAMS ((struct symtab *, int));
-/* If we use this declaration, it breaks because of fucking ANSI "const" stuff
- on some systems. We just have to not declare it at all, have it default
- to int, and possibly botch on a few systems. Thanks, ANSIholes... */
-/* extern char *strstr(); */
-
/* Path of directories to search for source files.
Same format as the PATH environment variable's value. */
current_source_symtab = PSYMTAB_TO_SYMTAB (cs_pst);
}
}
+ if (current_source_symtab)
+ return;
error ("Can't find a default source file");
}
/* FIXME, this goes to "delete dir"... */
if (dirname == 0)
{
- if (query ("Reinitialize source path to empty? ", ""))
+ if (query ("Reinitialize source path to empty? "))
{
free (source_path);
init_source_path ();
}
}
- if (p[-1] == '/')
+#ifndef WIN32
+ /* On win32 h:\ is different to h: */
+ if (SLASH_P (p[-1]))
/* Sigh. "foo/" => "foo" */
--p;
+#endif
*p = '\0';
while (p[-1] == '.')
name = current_directory;
goto append;
}
- else if (p[-2] == '/')
+ else if (SLASH_P (p[-2]))
{
if (p - name == 2)
{
if (name[0] == '~')
name = tilde_expand (name);
- else if (name[0] != '/' && name[0] != '$')
- name = concat (current_directory, "/", name, NULL);
+ else if (!ROOTED_P (name) && name[0] != '$')
+ name = concat (current_directory, SLASH_STRING, name, NULL);
else
name = savestring (name, p - name);
make_cleanup (free, name);
printf_filtered ("Contains %d line%s.\n", s->nlines,
s->nlines == 1 ? "" : "s");
- printf_filtered("Source language is %s.\n", language_str (s->language));
+ printf_filtered ("Source language is %s.\n", language_str (s->language));
+ printf_filtered ("Compiled with %s debugging format.\n", s->debugformat);
}
if (!path)
path = ".";
- if (try_cwd_first || string[0] == '/')
+#ifdef WIN32
+ mode |= O_BINARY;
+#endif
+
+ if (try_cwd_first || SLASH_P (string[0]))
{
+ int i;
filename = string;
fd = open (filename, mode, prot);
- if (fd >= 0 || string[0] == '/' || strchr (string, '/'))
+ if (fd >= 0)
goto done;
+ for (i = 0; string[i]; i++)
+ if (SLASH_P (string[i]))
+ goto done;
}
/* ./foo => foo */
- while (string[0] == '.' && string[1] == '/')
+ while (string[0] == '.' && SLASH_P (string[1]))
string += 2;
alloclen = strlen (path) + strlen (string) + 2;
len = strlen (p);
if (len == 4 && p[0] == '$' && p[1] == 'c'
- && p[2] == 'w' && p[3] == 'd') {
+ && p[2] == 'w' && p[3] == 'd') {
/* Name is $cwd -- insert current directory name instead. */
int newlen;
}
/* Remove trailing slashes */
- while (len > 0 && filename[len-1] == '/')
- filename[--len] = 0;
+ while (len > 0 && SLASH_P (filename[len-1]))
+ filename[--len] = 0;
- strcat (filename+len, "/");
+ strcat (filename+len, SLASH_STRING);
strcat (filename, string);
fd = open (filename, mode);
{
if (fd < 0)
*filename_opened = (char *) 0;
- else if (filename[0] == '/')
+ else if (ROOTED_P (filename))
*filename_opened = savestring (filename, strlen (filename));
else
{
/* Beware the // my son, the Emacs barfs, the botch that catch... */
*filename_opened = concat (current_directory,
- '/' == current_directory[strlen(current_directory)-1]? "": "/",
+ SLASH_CHAR
+ == current_directory[strlen(current_directory)-1]
+ ? "": SLASH_STRING,
filename, NULL);
}
}
-/* start-sanitize-mpw */
#ifdef MPW
- if (1) {
- printf("openp on %s, path %s mode %d prot %d\n returned %d",
- string, path, mode, prot, fd);
- if (*filename_opened)
- printf(" (filename is %s)", *filename_opened);
- printf("\n");
+ /* This is a debugging hack that can go away when all combinations
+ of Mac and Unix names are handled reasonably. */
+ {
+ extern int debug_openp;
+
+ if (debug_openp)
+ {
+ printf("openp on %s, path %s mode %d prot %d\n returned %d",
+ string, path, mode, prot, fd);
+ if (*filename_opened)
+ printf(" (filename is %s)", *filename_opened);
+ printf("\n");
+ }
}
-#endif
-/* end-sanitize-mpw */
+#endif /* MPW */
return fd;
}
/* Quick way out if we already know its full name */
if (s->fullname)
{
- result = open (s->fullname, O_RDONLY);
+ result = open (s->fullname, OPEN_MODE);
if (result >= 0)
return result;
/* Didn't work -- free old one, try again. */
}
}
- result = openp (path, 0, s->filename, O_RDONLY, 0, &s->fullname);
+ result = openp (path, 0, s->filename, OPEN_MODE, 0, &s->fullname);
if (result < 0)
{
/* Didn't work. Try using just the basename. */
p = basename (s->filename);
if (p != s->filename)
- result = openp (path, 0, p, O_RDONLY, 0, &s->fullname);
+ result = openp (path, 0, p, OPEN_MODE, 0, &s->fullname);
}
-/* start-sanitize-mpw */
#ifdef MPW
if (result < 0)
{
/* Didn't work. Try using just the MPW basename. */
p = (char *) mpw_basename (s->filename);
if (p != s->filename)
- result = openp (path, 0, p, O_RDONLY, 0, &s->fullname);
+ result = openp (path, 0, p, OPEN_MODE, 0, &s->fullname);
}
if (result < 0)
{
/* Didn't work. Try using the mixed Unix/MPW basename. */
p = (char *) mpw_mixed_basename (s->filename);
if (p != s->filename)
- result = openp (path, 0, p, O_RDONLY, 0, &s->fullname);
+ result = openp (path, 0, p, OPEN_MODE, 0, &s->fullname);
}
-#endif
-/* end-sanitize-mpw */
+#endif /* MPW */
+
if (result >= 0)
{
fullname = s->fullname;
int nlines = 0;
int lines_allocated = 1000;
int *line_charpos;
- long exec_mtime;
+ long mtime;
int size;
line_charpos = (int *) xmmalloc (s -> objfile -> md,
if (fstat (desc, &st) < 0)
perror_with_name (s->filename);
- if (exec_bfd)
+ if (s && s->objfile && s->objfile->obfd)
{
- exec_mtime = bfd_get_mtime(exec_bfd);
- if (exec_mtime && exec_mtime < st.st_mtime)
+ mtime = bfd_get_mtime(s->objfile->obfd);
+ if (mtime && mtime < st.st_mtime)
+ printf_filtered ("Source file is more recent than executable.\n");
+ }
+ else if (exec_bfd)
+ {
+ mtime = bfd_get_mtime(exec_bfd);
+ if (mtime && mtime < st.st_mtime)
printf_filtered ("Source file is more recent than executable.\n");
}
/* Have to read it byte by byte to find out where the chars live */
- line_charpos[0] = tell(desc);
+ line_charpos[0] = lseek (desc, 0, SEEK_CUR);
nlines = 1;
while (myread(desc, &c, 1)>0)
{
(int *) xmrealloc (s -> objfile -> md, (char *) line_charpos,
sizeof (int) * lines_allocated);
}
- line_charpos[nlines++] = tell(desc);
+ line_charpos[nlines++] = lseek (desc, 0, SEEK_CUR);
}
}
}
data = (char *) xmalloc (size);
old_cleanups = make_cleanup (free, data);
- if (myread (desc, data, size) < 0)
+ /* Reassign `size' to result of read for systems where \r\n -> \n. */
+ size = myread (desc, data, size);
+ if (size < 0)
perror_with_name (s->filename);
end = data + size;
p = data;
perror_with_name (s->filename);
}
- stream = fdopen (desc, FOPEN_RT);
+ stream = fdopen (desc, FDOPEN_MODE);
clearerr (stream);
while (nlines-- > 0)
printf_filtered ("^%c", c + 0100);
else if (c == 0177)
printf_filtered ("^?");
+#ifdef CRLF_SOURCE_FILES
+ else if (c == '\r')
+ {
+ /* Just skip \r characters. */
+ }
+#endif
else
printf_filtered ("%c", c);
} while (c != '\n' && (c = fgetc (stream)) >= 0);
CORE_ADDR start_pc, end_pc;
int i;
+ INIT_SAL (&sal); /* initialize to zeroes */
+
if (arg == 0)
{
sal.symtab = current_source_symtab;
perror_with_name (current_source_symtab->filename);
}
- stream = fdopen (desc, FOPEN_RT);
+ stream = fdopen (desc, FDOPEN_MODE);
clearerr (stream);
while (1) {
static char *buf = NULL;
/* Match! */
fclose (stream);
print_source_lines (current_source_symtab, line, line+1, 0);
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (builtin_type_int,
+ (LONGEST) line));
current_source_line = max (line - lines_to_list / 2, 1);
return;
}
perror_with_name (current_source_symtab->filename);
}
- stream = fdopen (desc, FOPEN_RT);
+ stream = fdopen (desc, FDOPEN_MODE);
clearerr (stream);
while (line > 1)
{
fclose (stream);
print_source_lines (current_source_symtab,
line, line+1, 0);
+ set_internalvar (lookup_internalvar ("_"),
+ value_from_longest (builtin_type_int,
+ (LONGEST) line));
current_source_line = max (line - lines_to_list / 2, 1);
return;
}
add_info ("source", source_info,
"Information about the current source file.");
-/* start-sanitize-mpw */
-#ifndef MPW_C
-/* end-sanitize-mpw */
add_info ("line", line_info,
- "Core addresses of the code for a source line.\n\
+ concat ("Core addresses of the code for a source line.\n\
Line can be specified as\n\
LINENUM, to list around that line in current file,\n\
FILE:LINENUM, to list around that line in that file,\n\
FUNCTION, to list around beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
+", "\
Default is to describe the last source line that was listed.\n\n\
This sets the default address for \"x\" to the line's first instruction\n\
so that \"x/i\" suffices to start examining the machine code.\n\
-The address is also stored as the value of \"$_\".");
-/* start-sanitize-mpw */
-#else
- add_info ("line", line_info,
- "Core addresses of the code for a source line. \n\
-Line can be specified as \n\
- LINENUM, to list around that line in current file, \n\
- FILE:LINENUM, to list around that line in that file, \n\
-Default is to describe the last source line that was listed. \n\n\
-The address is also stored as the value of \"$_\". ");
-#endif
-/* end-sanitize-mpw */
+The address is also stored as the value of \"$_\".", NULL));
add_com ("forward-search", class_files, forward_search_command,
- "Search for regular expression (see regex(3)) from last line listed.");
+ "Search for regular expression (see regex(3)) from last line listed.\n\
+The matching line number is also stored as the value of \"$_\".");
add_com_alias ("search", "forward-search", class_files, 0);
add_com ("reverse-search", class_files, reverse_search_command,
- "Search backward for regular expression (see regex(3)) from last line listed.");
+ "Search backward for regular expression (see regex(3)) from last line listed.\n\
+The matching line number is also stored as the value of \"$_\".");
-/* start-sanitize-mpw */
-#ifndef MPW_C
-/* end-sanitize-mpw */
add_com ("list", class_files, list_command,
- "List specified function or line.\n\
+ concat ("List specified function or line.\n\
With no argument, lists ten more lines after or around previous listing.\n\
\"list -\" lists the ten lines before a previous ten-line listing.\n\
One argument specifies a line, and ten lines are listed around that line.\n\
Two arguments with comma between specify starting and ending lines to list.\n\
+", "\
Lines can be specified in these ways:\n\
LINENUM, to list around that line in current file,\n\
FILE:LINENUM, to list around that line in that file,\n\
FUNCTION, to list around beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to list around the line containing that address.\n\
-With two args if one is empty it stands for ten lines away from the other arg.");
-/* start-sanitize-mpw */
-#else /* MPW_C */
- add_com ("list", class_files, list_command,
- "List specified function or line.\n\
-With no argument, lists ten more lines after or around previous listing. \n\
-One argument specifies a line, and ten lines are listed around that line. \n\
-Two arguments with comma between specify starting and ending lines to list. \n\
-Lines can be specified in these ways:\n\
-With two args if one is empty it stands for ten lines away from the other arg. ");
-#endif /* MPW_C */
-/* end-sanitize-mpw */
+With two args if one is empty it stands for ten lines away from the other arg.", NULL));
+
add_com_alias ("l", "list", class_files, 1);
add_show_from_set